大话设计模式之工厂模式
Posted 谈玄论道白中堂
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了大话设计模式之工厂模式相关的知识,希望对你有一定的参考价值。
工厂模式属于创建型设计模式,与之相关的有三个概念:简单工厂、工厂方法模式、抽象工厂模式。
原始设计
有一个披萨店PizzaStore,客户可以用orderPizza接口订自己喜欢的口味(type)的披萨:蛤蜊口味的或者是芝士味的:orderPizza(stringtype),比萨店会根据相应口味的pizza,进行prepare(擀面皮、加佐料),bake(烹饪)、cut(切片)、box(装盒)。
那么orderPizza代码直观是这样的:
Pizza orderPizza(String type) {
Pizzapizza;
if(type.equals(“cheese”)) {
pizza = new CheesePizza();
}else if (type.queals(“clam”)) {
pizza = new ClamPizza();
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
嗯,还不错,代码在十几行,也还简洁。
但是问题在于:如果要是披萨店又研发出来了其它口味,如苹果派口味的,腊肠口味的,或者素食味的Pizza不受欢迎,我们要把它从菜单里边去掉,这样我们就得修改orderPizza这个接口。
那么我们就要开始封装变化(代码中的红色部分)了。
简单工厂
简单工厂其实并不是设计模式,而是一种编程习惯(封装变化)。
我们搞一个PizzaFactory来处理创建对象的细节。
public class PizzaFactory{
publicPizza createPizza(string pizzaName) {
Pizzapizza = null;
if(type.equals(“cheese”)){
pizza= new CheesePizza();
} else if(type.queals(“clam”)) {
pizza= new ClamPizza();
}
returnpizza;
}
}
原来的披萨店的代码改成:
public class PizzaStore{
PizzaFactory factory;
public PizzaStore(PizzaFactory factory) {
this.factory =factory;
}
Pizza orderPizza(Stringtype) {
Pizza pizza;
pizza =factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
有了这个工厂之后,客户界面的代码orderPizza就可以不变了。
你可能会问,这样做只是把变化挪到了PizzaFactory里边了。新增一个pizza的时候,createPizza仍然需要修改。
对,但PizzaFactory实际上可以有很多客户,比如PizzaShopMenu(菜单)也会用到这个工厂来获取菜单,或者HomeDelivary外卖。这些类不需要知道CheesePizza、ClamPizza这么多细节,只和PizzaFactory打交道即可。
工厂方法模式
如果披萨店经营得好,做成了必胜客,那么大家都想在自己家附近能吃到必胜客。那么必胜客在苏州可能就要做的清淡一点,如果在成都开店的话,可能就要做的重口味一些。
那么如果我们仍然运用简单工厂的方法的话,我们需要两种工厂:szPizzaFactory、cdPizzaFactory。
szPizzaFactory = new szPizzaFactory();
PizzaStore szStore = new PizzaStore(szPizzaFactory);
szStore.orderPizza(“cheese”);
cdPizzaFactory = new cdPizzaFactory();
PizzaStore cdStore = new PizzaStore(cdPizzaFactory);
cdStore.orderPizza(“cheese”);
那么这样各加盟店除了口味之外,灵活性又太大了,比如,它可能就不切片了,采用的盒子包装也开始自由发挥。
那么怎么样做质量控制又能让各加盟店保留一定的弹性呢?
public abstractclass PizzaStore{
PizzaFactory factory;
public PizzaStore(PizzaFactoryfactory) {
this.factory = factory;
}
publicPizza orderPizza(String type) {
Pizza pizza;
pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
abstract Pizza createPizza(String type);
}
请注意上述红字部分。我们把工厂对象移到createPizza()方法中,其它流程保持原有的质量控制。
创建者类:
产品类:
在各地pizza加盟店(子类)中,可以通过实现createPizza(和产品子类进行关联)创建符合当地消费者口味的芝士味披萨,蛤蜊味披萨。又能保持其它方面的质量不变(比如:不能偷懒省去切片流程免得砸牌子。)
是时候引出工厂方法模式的正式定义了:
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
在编写创建这类时,不需要知道实际创建的产品是哪一个。选择了使用哪个子类,自然就决定了实际创建的产品是什么。(我口味比较重,我选择成都的披萨加盟店,因此选的芝士披萨是带点麻辣味的)。
该模式对依赖关系的改变:
如果我们用的是原始方式进行编码的话,那么PizzaStore会依赖于具体的类cdStyleCheesePizza, cdStyleClamPizza, szStyleCheesePizza,szStyleClamPizza。随着加盟店的膨胀和口味的丰富,依赖关系会越来越多。代码里减少对具体类的依赖是好事,因此根据设计原则-依赖倒置原则(DIP,要依赖抽象不要依赖具体类),将它改成只依赖于抽象出来Pizza了。
抽象工厂模式
经过一段时间的运营,老板发现,有某些加盟店,为了利润考虑,采用了低价的原料。
为了加盟店的长期发展,老板决定,把原料的质量也控制起来。
老板呢,建造了一个工厂来生产原料:
public interface PizzaIngredientFactory{
publicDough createDough();
publicSauce createSauce();
publicCheese createCheese();
public ClamcreateClam();
}
成都区域的原料工厂和苏州区域的原料工厂分别继承PizzaIngredientFactory来实现每一种原来的创建方法。
同样,需要实现一组原料类工厂使用,如ReggianoCheese,ThickCrustDough等,这些类可以在各区域的原料工厂之间共享。
组织起它们,以运转加盟店。
组织过程比如:
在CheesePizza里边的prepare方法中调用原料工厂的原料来擀面皮,加佐料。等等……
从PizzaStore的观点来看,类图是这样的:
抽象工厂的模式定义如下:
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
抽象工厂和工厂方法的区别
看起来抽象工厂和工厂方法很相似,那么他们的区别和共性有哪些呢?
都负责创建对象
a) 工厂方法用的是继承
b) 抽象工厂用的是对象的组合
抽象工厂创建整个产品家族,而工厂方法是创建一个产品。因此,抽象工厂需要一个大的接口,而工厂方法只需要一个方法。
抽象工厂经常使用工厂方法来实现具体的工厂。但这些具体的工厂纯粹只是用来创建产品;而工厂方法的creator中实现的代码通常会用到子类所创建的具体类型。
两者都能将对象的创建封装起来,使应用程序解耦,并降低对特定实现的依赖。当需要创建产品家族和想让制造的相关产品集合起来时,可以用抽象工厂。而工厂方法可以把客户代码从需要实例化的具体类中解耦。或者如果目前还不知道将来需要实例化哪些具体类的时候可以用它。
素材来自《Head First设计模式》
编辑:白中堂
以上是关于大话设计模式之工厂模式的主要内容,如果未能解决你的问题,请参考以下文章