设计模式6 工厂模式

定义

"工厂模式"分为三类:

  • 简单工厂模式(Simple Factory)
  • 工厂方法模式(Factory Method)
  • 抽象工厂模式(Abstract Factory)

简单工厂模式可以帮助开发人员创建不同类型的对象,将对象创建交给专门的工厂类处理,而不是直接将对象实例化。
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化哪一个。工厂方法模式把实例化推迟到子类中。
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

例子均来自《HEAD First设计模式》披萨店

简单工厂模式

当我们在进行对象的创建时,可能会需要在很多对象之间进行选择。例如在进行初始化操作时,需要初始化很多东西,导致代码逻辑比较长,在后续新增需求的时候可能会发生修改。例如披萨店中,可能需要不同的披萨类型:

Pizza pizza;
if (pizzaType.Equals("cheese"))
	pizza = newCheesePizza();
else if(pizzaType.Equals("greek"))
	pizza = newGreekPizza();
else if(pizzaType.Equals("pepperoni"))
	pizza = newPepperoniPizza();

为了防止对这块代码的修改,可以选择将这一块对象创建的代码抽离出来,封装进一个简单披萨工厂:

public class SimplePizzaFactory
{
    public createPizza(string pizzaType)
    {
        Pizza pizza = null;
        if(pizzaType.Equals("cheese"))
            pizza = newCheesePizza();
        else if (pizzaType.Equals("pepperoni"))
            pizza = newPepperoniPizza();
        else if(pizzaType.Equals("clam"))
            pizza = newCalmPizza();
        else if(pizzaType.Equals("veggie"))
            pizza = newVeggiePizza();
        return pizza;
    }
}

这个SimplePizzaFactory的作用就是帮助客户创建披萨。这样在进行修改时只需要修改这个类就可以了。因此,披萨店逻辑可以这样写:

public class PizzaStroe
{
	SimplePizzaFactory simplePizzaFactory;
	Public Pizza(SimplePizzaFactory sp)
	{
		this.simplePizzaFactory = sp;
	}
	Pizza OrderPizza(string type)
	{
		Pizza pizza;
		pizza = simplePizzaFactory.createPizza(type);
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();
		return pizza;
	}
}

类图如下所示:

Pizza +prepare() +bake() +cut() +box() CheesePizza VegglePizza SimplePizzaFactory +createPizza() PizzaFactory -orderPizza

其实工厂模式并不是一种真正的设计模式,反而更像是一种编程习惯。

工厂方法模式

在披萨业务扩展中,可能会有更多的加盟店,这些店对于披萨的处理可能并不相同。此时如果把OrderPizza()放在SimplePizzaFactory中,可能弹性不够,比如不同店里面对于披萨的切、烤等工序不同。

可以把CreatePizza()方法放回到PizzaStore中,但是要把它设置为抽象方法,然后为每一个区域加盟店创建一个PizzaStore的子类。
这样代码就变成了:

public abstract class PizzaStore
{
    public PizzaOrderPizza(string pizzaType)
    {
        Pizza pizza = createPizza(pizzaType);
        pizza.Prepare();
        pizza.Bake();
        pizza.Cut();
        pizza.Box();
        return pizza;
    }
    public abstract createPizza(string pizzaType);//把工厂对象移到该方法中,该方法为抽象方法
}

这样在建立纽约的披萨店的时候就可以使用:

public class NYPizzaStore extends PizzaStore
{
    public createPizza(string pizzaType)
    {
		if(pizzaType.equals("cheese"))
		{
			return new NYCheesePizza();
		}else if()
		{//...}
	}
}

这样就可以让子类做决定,子类负责定义自己的createPizza()方法。
因此,工厂方法的核心是:

abstract Product factoryMethod(String type)

工厂方法模式的结构如下图所示(图源:工厂模式):
请添加图片描述
可以看到,一个orderPizza()方法和工厂方法联合起来,就可以成为这样一个框架,这可以看做是一个平行的类层级。
对于简单工厂和工厂方法之间的关系,简单工厂把所有的事情在一个地方都处理了,工厂方法中将这个下放给了PizzaStore类。

依赖倒置原则

在这种披萨店里面,依赖会很多,例如在创建披萨的函数中,会依赖许许多多的披萨类型,如纽约芝士披萨,芝加哥菜披萨等等,PizzaStore会依赖所有的披萨对象,如果有修改需要修改很多地方。
在代码中应该减少依赖,面向对象设计原则:
依赖倒置原则(Dependency Inversion Principle)
要依赖抽象,不要依赖具体类
这就意味着:不能让高层组件依赖底层组件,而且不管高层、底层组件,两者都应该依赖于抽象。
例如在这个披萨店的例子中,不应该让高层的披萨店依赖底层的披萨,而是应该让披萨依赖于抽象披萨接口,披萨店依赖于披萨接口。
Q:如何避免违反依赖倒置原则?

  • 变量不可以持有具体类的引用
    如果使用new,则会持有具体类的引用,可以用工厂来避开这样的做法
  • 不要让类派生自具体类
    如果派生自具体类,就会依赖具体类(可以派生自一个抽象类或接口)
  • 不要覆盖基类中已实现的方法
    如果覆盖基类已实现的方法,那么你的基类就不是一个真正适合被继承的抽象。基类中已实现的方法,应该由所有的子类共享。

抽象工厂模式

如果在未来想新增一个原料工厂,为所有的加盟店提供原料,每个地方所采用的的原料是不同的。
首先定义一个原料工厂接口,工厂需要生产面团、酱料、芝士等:

public interface PizzaIngredientFactory {
    public Dough createDough();
    public Sauce createSauce();
    public Cheese createCheese();
    public Veggies[] createVeggies();
    public Pepperoni createPepperoni();
    public Clams createClam();
}

那么对于纽约的原料工厂,可以这样实现:

public class NYPizzaIngredientFactory implements PizzaIngredientFactory{
    public Dough createDough(){
        return new ThinCrustDough();
    }
    public Sauce createSauce(){
        return new MarinaraSauce();
    }
    public Cheese createCheese(){
        return new ReggianoCheese();
    }
    public Veggies[] createVeggies(){
        Veggies veggies[]={new Garlic(),new Onion(),new Mushroom(),new RedPepper()};
        return veggies;
    }
    public Pepperoni createPepperoni(){
        return new SlicedPepperoni();
    }
    public Clams createClam(){
        return new FreshClams();
    }
}

那么对于一个抽象披萨类:

public abstract class Pizza {
    String name;
    String dough;
    String sauce;
    Veggies veggies[];
    Cheese cheese;
    Pepperoni pepperoni;
    Clams clam;
    abstract void prepare();
    void bake(){
        System.out.println("Bake for 25 minutes at 350");
    }
    void cut(){
        System.out.println("Cutting the pizza into diagonal slices");
    }
    void box(){
        System.out.println("Place pizza in official PizzaStore box");
    }
    void setName(String name){
        this.name=name;
    }
    public String getName(){
        return name;
    }
}

那么对于芝士披萨,可以定义为:

public class CheesePizza extends Pizza{
    PizzaIngredientFactory ingredientFactory;
    //作Pizza需要工厂提供原材料,构造函数中获得一个工厂,并把工厂存在一个变量中
    public CheesePizza(PizzaIngredientFactory ingredientFactory){
        this.ingredientFactory=ingredientFactory;
    }
    void prepare(){
        System.out.println("Prepareing "+name);
        dough=ingredientFactory.createDough();
        sauce=ingredientFactory.createSauce();
        cheese=ingredientFactory.createCheese();
    }
}

那么纽约披萨店就可以这样实现:

public class NYPizzaStore extends PizzaStore{
    Pizza createPizza(String item){
        Pizza pizza=null;
        //创建披萨原料工厂
        PizzaIngredientFactory ingredientFactory=new NYPizzaIngredientFactory();
        if(item.equals("cheese")){
            pizza=new CheesePizza(ingredientFactory);
            pizza.setName("New York Style Cheese Pizza");
        }else if(item.equals("veggie")){
            pizza=new VeggiePizza(ingredientFactory);
            pizza.setName("New York Style Veggie Pizza");
        }else if(item.equals("clam")){
            pizza=new ClamPizza(ingredientFactory);
            pizza.setName("New York Style Clam Pizza");
        }else if(item.equals("pepperoni")){
            pizza=new PepperoniPizza(ingredientFactory);
            pizza.setName("New York Style Pepperoni Pizza");
        }
        return pizza;
    }
}

抽象工厂模式(Abstract Factory Pattern)
提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
工厂方法模式和抽象工厂模式对比:抽象工厂模式可以更方便的创建出各种各样的披萨工厂,将代码从实际的工厂中解耦,客户只需要使用其中一个工厂,而不需要实例化任何产品对象,如奶酪对象、面饼对象。工厂方法模式采用继承和子类来决定要创建哪个对象;抽象工厂模式使用组合将创建对象的任务委托给其他类。

参考

工厂模式
关于三种工厂模式的总结
Head First 设计模式之工厂模式(Factory Pattern)
工厂模式——Head First
漫画:设计模式之 “工厂模式”
工厂模式

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值