标签:
如今鼓励大众创业万众创新,身在吃货之都成都,我打算投入餐饮行业,可惜穷鬼一个,手头没多少银子,那就从小面馆开启我的创业之路吧。说干就干,简单筹备后我的面馆就开张接客啦!
public class Constant {
//牛肉面
public static String BEEF_NOODLES = "BeefNoodles";
//担担面
public static String DAN_DAN_NOODLES = "DanDanNoodles";
//肥肠面
public static String INTESTINES_NOODLES = "IntestinesNoodles";
//甜水面
public static String SWEET_NOODLES = "SweetNoodles";
//燃面
public static String BURNING_NOODLES = "BurningNoodles";
}
public class NoodleRestaurant {
//点餐
public Noodles orderNoodles(String type) {
Noodles noodles;
if (Constant.BEEF_NOODLES.equals(type)) {
noodles = new BeefNoodles();
} else if(Constant.DAN_DAN_NOODLES.equals(type)){
noodles = new DanDanNoodles();
} else if(Constant.INTESTINES_NOODLES.equals(type)) {
noodles = new IntestinesNoodles();
} else if (Constant.SWEET_NOODLES.equals(type)) {
noodles = new SweetNoodles();
} else {
noodles = new BurningNoodles();
}
noodles.prepare();
noodles.cook();
noodles.bowl();
return noodles;
}
}
OK,店铺搞定,开门营业,随着吃客越来越多,我想增加新的品种:杂酱面、豌豆面…夏天到了,我还想增加凉面。发现每增加一个品种,我都得去NoodleRestaurant改动一番,这跟咱们之前一直强调的对扩展开放,对修改关闭的原则相矛盾。而且NoodleRestaurant中new了太多具体类,而代码绑着具体类会导致代码更脆弱,更缺乏弹性。想想我们的NoodleRestaurant依赖了多少具体类?
(图a)
来数一数,NoodleRestaurant依赖了多少个具体类?而且这还只是暂时的,随着菜单品种的不断增加,这个依赖将变得庞大无比。生意越来越好,我打算在重庆开一家分店,重庆人的口味跟成都不同,我又需要增加重庆小面、豌豆面,同样是牛肉面,重庆口味偏麻偏辣,成都口味偏香,天呐,NoodleRestaurant里的依赖越来越乱了,别慌,接下来要讲的工厂模式将帮你从复杂的依赖中脱困。
原本是由一个对象负责所有具体类的实例化,我们现在对NoodleRestaurant做一些改变,让一群子类来负责实例化。
public abstract class NoodleRestaurant {
public Noodles orderNoodles(String type) {
Noodles noodles;
noodles = createNoodles(type);
noodles.prepare();
noodles.cook();
noodles.bowl();
return noodles;
}
//创建Noodles对象
protected abstract Noodles createNoodles(String type);
}
这里的createNoodles
方法就是工厂方法,工厂方法用来处理对象的创建,并将创建行为封装在子类中,这样,NoodleRestaurant就和具体Noodles类解耦了。
/**
* 成都面馆
* Created by sarahzhou on 16/6/21.
*/
public class CDNoodleRestaurant extends NoodleRestaurant {
@Override
protected Noodles createNoodles(String type) {
Noodles noodles;
if (Constant.BEEF_NOODLES.equals(type)) {
noodles = new CDBeefNoodles();
} else if(Constant.DAN_DAN_NOODLES.equals(type)){
noodles = new DanDanNoodles();
} else if(Constant.INTESTINES_NOODLES.equals(type)) {
noodles = new IntestinesNoodles();
} else if (Constant.SWEET_NOODLES.equals(type)) {
noodles = new SweetNoodles();
} else if (Constant.BURNING_NOODLES.equals(type)) {
noodles = new BurningNoodles();
} else {
noodles = new CDColdNoodles();
}
return noodles;
}
}
/**
* 重庆面馆
* Created by sarahzhou on 16/6/21.
*/
public class CQNoodleRestaurant extends NoodleRestaurant {
@Override
protected Noodles createNoodles(String type) {
Noodles noodles;
if (Constant.BEEF_NOODLES.equals(type)) {
noodles = new CQBeefNoodles();
} else if (Constant.SMALL_NOODLES.equals(type)) {
noodles = new SmallNoodles();
} else if (Constant.LAOMA_DUMPLINGS.equals(type)) {
noodles = new LaomaDumplings();
} else if (Constant.PEAS_NOODLES.equals(type)) {
noodles = new PeasNoodles();
} else {
noodles = new CQColdNoodles();
}
return noodles;
}
}
这样我就可以在面馆子类中决定Noodles的种类和口味啦。对于牛肉面Constant.BEEF_NOODLES
,在成都面馆中我做成都口味的牛肉面CDBeefNoodles
,在重庆面馆中我做适合重庆人口味的牛肉面CQBeefNoodles
。超类从来不管细节,子类会自行负责这一切。工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。
(图b)
(图c)
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到了子类。我要新开店,只需创建restaurant子类继承NoodleRestaurant即可,我要改变成都店的菜单,只需更改成都店即可。
不能让高层组件依赖低层组件,而且,不管高层或底层组件,都应该依赖于抽象。图a中的依赖是自上而下的,高层组件NoodleRestaurant依赖具体的低层组件。使用了工厂方法模式之后,依赖关系变成了这样:
高层组件NoodleRestaurant依赖同层次的抽象组件Noodles,而CDBeefNoodles等低层组件转而依赖高层组件Noodles,这跟一开始的高层组件依赖低层组件是不是相反了呢?因此称为依赖倒置。依赖倒置可以使我们的设计松耦合,更有弹性,更容易扩展。在设计中遵循依赖倒置,应该遵守以下原则:
1. 变量不可以持有具体类的引用
2. 不要让类派生自具体类,请派生自一个抽象
3. 不要覆盖基类中已实现的方法;如果覆盖基类已实现的方法,那么你的基类就不是一个真正适合被继承的抽象,基类中已实现的方法应该由所有的子类共享。
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。抽象工厂模式是用来创建整个产品家族的,而工厂方法模式单单是创建一个产品,抽象工厂模式中利用的就是工厂方法模式。
工厂方法使用继承,把对象的创建委托给子类,子类实现工厂方法来创建对象。抽象工厂使用对象组合,对象的创建被实现在工厂接口所暴露出来的方法中。它们都是通过减少应用程序和具体类之间的依赖促进松耦合。
每种面食的制作流程无非都是:准备食材、煮面、盛碗。差别就在准备食材,毕竟每种面食所需的具体材料是不同的嘛:面条、肉、酱料、蔬菜等都是不一样的。
public abstract class Noodles {
//面条
Flour flour;
//肉
Meat meat;
//酱料
Sauce sauce;
//蔬菜
Vegetables vegetables;
//准备食材
public abstract void prepare();
//煮面
public void cook() {
System.out.println("将原料加工成熟食.");
}
//盛碗
public void bowl() {
System.out.println("将食物装入碗中.");
}
}
准备4种食材的工作由prepare()
完成,具体逻辑由子类实现,那么又有新的问题了,食材从哪里来?谁提供呢?我们打算在成都和重庆各建一所原料工厂,先把工厂建起来吧。
/**
* 原料工厂
* Created by sarahzhou on 16/6/21.
*/
public interface IngredientFactory {
//面粉
Flour createFlour();
//肉
Meat createMeat();
//酱料
Sauce createSauce();
//蔬菜
Vegetables createVegetables();
}
/**
* 成都原料工厂
* Created by sarahzhou on 16/6/21.
*/
public class CDIngredientFactory implements IngredientFactory {
//成都产的面粉
@Override
public Flour createFlour() {
return new CDFlour();
}
@Override
public Meat createMeat() {
return new BeefMeat();
}
//成都口味的酱料;
@Override
public Sauce createSauce() {
return new CDSauce();
}
//不同地区的人喜欢吃的蔬菜也不一样,成都人喜欢吃豌豆尖;
@Override
public Vegetables createVegetables() {
return new CDVegetables();
}
}
/**
* 重庆原料工厂
* Created by sarahzhou on 16/6/21.
*/
public class CQIngredientFactory implements IngredientFactory {
//重庆产的面粉;
@Override
public Flour createFlour() {
return new CQFlour();
}
//猪肉;
@Override
public Meat createMeat() {
return new PorkMeat();
}
//重庆口味的酱料;
@Override
public Sauce createSauce() {
return new CQSauce();
}
//重庆人喜欢吃生菜;
@Override
public Vegetables createVegetables() {
return new CQVegetables();
}
}
原料工厂建造完毕了,面馆开始进货营业吧。
public abstract class NoodleRestaurant {
public Noodles orderNoodles(String type) {
Noodles noodles;
//调用子类实现的createNoodles方法;
noodles = createNoodles(type);
noodles.prepare();
noodles.cook();
noodles.bowl();
return noodles;
}
protected abstract Noodles createNoodles(String type);
}
/**
* 成都面馆
* Created by sarahzhou on 16/6/21.
*/
public class CDNoodleRestaurant extends NoodleRestaurant {
IngredientFactory ingredientFactory;
//绑定原料工厂
public CDNoodleRestaurant(IngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
@Override
protected Noodles createNoodles(String type) {
Noodles noodles;
if (Constant.BEEF_NOODLES.equals(type)) {
noodles = new CDBeefNoodles(ingredientFactory);
} else if (Constant.DAN_DAN_NOODLES.equals(type)) {
noodles = new DanDanNoodles(ingredientFactory);
} else if (Constant.INTESTINES_NOODLES.equals(type)) {
noodles = new IntestinesNoodles(ingredientFactory);
} else if (Constant.SWEET_NOODLES.equals(type)) {
noodles = new SweetNoodles(ingredientFactory);
} else if (Constant.BURNING_NOODLES.equals(type)) {
noodles = new BurningNoodles(ingredientFactory);
} else {
noodles = new CDColdNoodles(ingredientFactory);
}
return noodles;
}
}
/**
* 重庆面馆
* Created by sarahzhou on 16/6/21.
*/
public class CQNoodleRestaurant extends NoodleRestaurant {
IngredientFactory ingredientFactory;
//绑定原料工厂
public CQNoodleRestaurant(IngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
@Override
protected Noodles createNoodles(String type) {
Noodles noodles;
if (Constant.BEEF_NOODLES.equals(type)) {
noodles = new CQBeefNoodles(ingredientFactory);
} else if (Constant.SMALL_NOODLES.equals(type)) {
noodles = new SmallNoodles(ingredientFactory);
} else if (Constant.LAOMA_DUMPLINGS.equals(type)) {
noodles = new LaomaDumplings(ingredientFactory);
} else if (Constant.PEAS_NOODLES.equals(type)) {
noodles = new PeasNoodles(ingredientFactory);
} else {
noodles = new CQColdNoodles(ingredientFactory);
}
return noodles;
}
}
相应地,我们的Noodles实现类就变成了以下这样,把工厂传给每个面食,以便面食能从工厂中取得原料:
public class BurningNoodles extends Noodles {
IngredientFactory ingredientFactory;
public BurningNoodles(IngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
@Override
public void prepare() {
System.out.println("Preparing burning noodles.");
flour = ingredientFactory.createFlour();
meat = ingredientFactory.createMeat();
sauce = ingredientFactory.createSauce();
vegetables = ingredientFactory.createVegetables();
}
}
好了,回头看看我们的代码,有底层组件依赖高层组件的吗?显然没有了,咦,有客人来了,担担面一碗:
public class FactoryTestDrive {
@Test
public void test1() {
//创建成都原料工厂
IngredientFactory ingredientFactory = new CDIngredientFactory();
//创建成都面馆,并绑定原料工厂
NoodleRestaurant noodleRestaurant = new CDNoodleRestaurant(ingredientFactory);
//担担面一碗
noodleRestaurant.orderNoodles(Constant.DAN_DAN_NOODLES);
}
}
看到没,具体类型都是在运行时确定的。
提到Spring,不得不提控制反转(Inversion of Control)和依赖注入(Dependency Injection)。传统的创建对象的方式是new,这是个主动的行为,控制权在使用者,我需要哪个对象,我去new就完事儿了。Spring是个大容器,也是个大工厂,我只需要在Spring的配置文件中配置我的依赖,告诉Spring我需要什么,Spring工厂会解析这个配置文件,把我的依赖对象创建好,注入到我的实例中。这样子,控制权就移交给了Spring工厂,这就叫做控制反转、依赖注入。
标签:
原文地址:http://blog.csdn.net/chi_wawa/article/details/51728468