第八章 雷锋依然在人间 - 工厂方法模式

这一章讲的是简单工厂模式和工厂方法模式的比较。
    先是说,小菜有个同学薛磊风(学雷锋),平时默默无闻,一天不幸出了车祸,然后同学们就去医院看望他,才知道他三年如一日地为一位孤寡老人做好事,然后他现在住院了嘛,就拜托小菜他们替他照顾一下老人家。
    坦白讲呢,如果是我的话,我做不到这么伟大,我只想照顾好自己的家人就够了。
    然后呢,小菜和大鸟说了这个事情,他们就开始谈论设计模式了,今天讨论的是简单工厂和工厂方法模式。
    简单工厂就是第一章讲的那个,在工厂类中有switch来生成对应的运算子类,而工厂方法模式呢,是在抽象工厂下面又扩展了对应的加减乘除四个工厂,有什么区别呢?
    在简单工厂中,如果要新增运算,那么就要修改工厂类,增加switch的分支,这就违背了开-闭原则,而工厂方法中,新增运算是新增对应的运算工厂类,这样不违背开闭原则。
    简单工厂模式最大的优点是工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态的实例化相关的类,对于客户端来说,去除了与具体产品相关的依赖。比如计算器例子中,客户端不用管该用哪个类的实例,只需要把运算符传给工厂就行。但是不可避免的违背了开闭原则,因为新增运算符势必需要修改工厂类。

    下面来重点理解一下工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪个子类,把一个类的实例化延迟到子类中。
    工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在的,也就是说,工厂方法模式把简单工厂的内部判断逻辑移到了客户端中,你想要增加功能,本来是改工厂类,现在是修改客户端。

回到这一章的故事上来,用代码来表示帮助老人这个故事:

/***
 * 雷锋抽象类
 */
public abstract class LeiFeng {

    //    扫地
    abstract void sweep();

    //    洗衣服
    abstract void wash();

    //    买米
    abstract void buyRice();

}

现在三个学生去做好事,学生类Student继承LeiFent,在客户端中这样调用:

public static void main(String[] args) {

        LeiFeng student1 = new Student();
        LeiFeng student2 = new Student();
        LeiFeng student3 = new Student();

        student1.sweep();
        student2.wash();
        student3.buyRice();
    }

如果此时这三个不是学生,而是志愿者,那么就需要修改每个new Student()的地方,改成new Volunteer(),
如果用简单工厂来描述,就是:

switch 
  "学生" :
    new Student();
    break;
  "志愿者":
    new Volunteer();
    break;

每个实例化学生的地方,都要写Factory.createLeiFeng("学生"),如果需要改成志愿者,那么每个地方都要修改;

而如果用工厂方法模式来描述这个例子,就是:
先创建StudentFactory和VolunteerFactory两个工厂类,继承LeiFengFactory,在客户端中:

LeiFengFactory leiFengFactory = new StudentFactory();
LeiFeng leiFeng1 = leiFengFactory.createLeiFeng();
LeiFeng leiFeng2 = leiFengFactory.createLeiFeng();
LeiFeng leiFeng3 = leiFengFactory.createLeiFeng();

leiFeng1.buyRice();
leiFeng2.sweep();
leiFeng3.wash();

这样,如果要改成志愿者做好事,那么只需要修改new StudentFactory()为new VolunteerFactory(),只需要改这一个地方就行。

工厂方法模式比简单工厂要高明一点,它既封装了创建对象的过程,又克服了开闭原则,缺点是每加一个产品,就要对应增加一个工厂类。 -- “反射,可以解决这个问题。”

你可能感兴趣的:(第八章 雷锋依然在人间 - 工厂方法模式)