大话设计模式之工厂模式

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的观点来看,类图是这样的:


抽象工厂的模式定义如下:

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。


抽象工厂和工厂方法的区别

看起来抽象工厂和工厂方法很相似,那么他们的区别和共性有哪些呢?

  1. 都负责创建对象

  2. a)      工厂方法用的是继承

  3. b)     抽象工厂用的是对象的组合

  4. 抽象工厂创建整个产品家族,而工厂方法是创建一个产品。因此,抽象工厂需要一个大的接口,而工厂方法只需要一个方法。

  5. 抽象工厂经常使用工厂方法来实现具体的工厂。但这些具体的工厂纯粹只是用来创建产品;而工厂方法的creator中实现的代码通常会用到子类所创建的具体类型。


两者都能将对象的创建封装起来,使应用程序解耦,并降低对特定实现的依赖。当需要创建产品家族和想让制造的相关产品集合起来时,可以用抽象工厂。而工厂方法可以把客户代码从需要实例化的具体类中解耦。或者如果目前还不知道将来需要实例化哪些具体类的时候可以用它。

 

素材来自《Head First设计模式》


编辑:白中堂

以上是关于大话设计模式之工厂模式的主要内容,如果未能解决你的问题,请参考以下文章

大话设计模式之简单的工厂模式

大话设计模式之简单工厂模式

大话设计模式之简单工厂模式

java 之 抽象工厂模式(大话设计模式)

大话设计模式第八章之简单工厂模式

大话设计模式之简单工厂模式