再说工厂方法

再说工厂方法

其实,在上一篇关于工厂方法解析的文章中,对于里面的编程的举例其实是不太满意的。

有一千个观众就有一千个哈姆雷特。对于工厂方法,在网上所查到的解释却有很大的不同,所以这里再写一篇文章,总结下我对于关于工厂方法的见解。


定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。

在《大话设计模式》中,作者列举了对工厂方法的使用。

//原本的代码
Vlounteer student = new Vlounteer();

//------
//使用工厂方法的代码
VlounteerFactory factory = new StudentFactory();
Vlounteer student = factory.createVlounteer();

其实,个人认为,作者对于工厂方法的讲解不太好,或者是我并没有理解清楚作者的意图。从作者的举例以及说明来看,这样做的做法就是student的创建是不依赖于new关键字的,这样能够使student的创建依赖于抽象的factory,而当需要替换student的时候,只需要替换new StudentFactory()即可。

看到这里,或许大多数人都会有一个疑惑?为什么这里非要多此一举的新建一个VlounteerFactory,如果是依赖抽象,面向对象特点之一的多态不久能完全满足么?


而《Head First 设计模式》讲解的却是比较详细,而且多看几遍,恰能解决我的疑惑。

这里先说结论:

设计模式最终的目标便是对修改关闭,对扩展开放,而实现这一目标的方式之一便是依赖倒转,工厂方法作为创建型模式之一,主要是用来解决创建对象时的问题,详细一点说便是解决对象的之间的依赖的一种手段。

这里直接拿《Head First 设计模式》中的例子来看:

粗略的说: PizzaStore类中包含了Pizza,但是Pizza的类型有很多种,并且不同地方的披萨也有所不同,PizzaStore需要根据用户的选择来生产不同Pizza,那么,我们便可以说PizzaStore依赖Pizza,我们可以使用依赖倒置原则来设计PizzaStore

public class PizzaStore{
    //生产pizza的简单工厂类
    private PizzaFactory factory;

    public PizzaStore(PizzaFactory pizza){
        this.pizza=pizza;
    }

    public Pizza orderPizza(String type){
        Pizza pizza = factory.create(type);
        pizza.cook();
        pizza.cut();
        pizza.box();
        return pizza;
    }

}

简单说上面的代码就是PizzaStore()不用管传入的PizzaFactory的具体类型,无论是NewYorkPizzaFactroy、ChicagoPizzaFactory,它只负责根据用户的传入的类型获取Pizza,然后将Pizza加工即可,而在新增PizzaFactory的时候,完全不用修改PizzaStore的代码,这便是依赖倒转

但是,这样的代码会带来一个问题,那便是我们直接将PizzaFactory暴露给了用户,而用户完全可以绕过PizzaStore直接通过PizzaFactory()直接获取未加工的Pizza,如果在某些情况下,你想完全控制Pizza,而将PizzaFactory隐藏起来,也就是不通过依赖注入的方式传入PizzaStore,这个时候,就可以使用工厂方法的技巧。

public abstract class PizzaStore{

    //不同的子类实现不同的createPizza方法
    protected abstract Pizza createPizza(String type);

    public Pizza orderPizza(String type){
        Pizza pizza = createPizza(type);
        pizza.cook();
        pizza.cut();
        pizza.box();
        return pizza;
    }

}

这里,我们通过构建一个抽象的createPizza方法,让每个子类自己根据自己的情况实现createPizza()方法即可,比如NewYorkPizzaStory或者ChicagoPizzaStory,效果和使用依赖注入的版本一样,但是用户并不知道NewYorkPizzaFactroy、ChicagoPizzaFactory等的存在。


到这里,我们根据上面的例子大概就能明白了,工厂方法模式是实现依赖注入效果的另一种方式

通过工厂方法,当某个对象所依赖的对象可能会频繁变化的时候,我们可以分离变化与不变化的部分,从而实现依赖之间的解耦。

工厂方法和依赖倒转的不同便是在于:依赖倒转中所依赖的对象是在实例化的时候根据传入的对象而确定的,而工厂方法中所依赖的对象是在new具体的对象类型时便已经被隐式决定。

尊重劳动成果,转载注明出处