设计模式之工厂模式

《Head First 设计模式》阅读笔记

Posted by wangtiegang on September 22, 2019

工厂模式分为简单工厂,工厂方法模式和抽象工厂模式。

简单工厂

简单工厂其实不是一个设计模式,反而更像是一种编程习惯,它是指创建对象时不再直接使用 new ,而是把创建的过程委托给一个工厂类,这样客户端类不再依赖具体的实现类,只需要依赖工厂类,给出具体的参数给工厂类,工厂类就会返回对应的实例对象。这种适合在根据大量判断条件创建不同类型时使用,工厂将具体的对象跟客户端解藕,并且更加具有可重用性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/**
 * 简单披萨工厂
 */
public class SimplePizzaFactory {

    /**
     * 根据不同类型创建对应的披萨
     * @param type 披萨类型
     * @return
     */
    public Pizza createPizza(String type){

        if (type.equals("cheese")){
            return new CheesePizza();
        }else if(type.equals("clam")){
            return new ClamPizza();
        }else {
            return new CheesePizza();
        }

    }

}

/**
 * 客户端
 */
public class PizzaStore {

    /**
     * 简单披萨工厂
     */
    SimplePizzaFactory factory;

    public PizzaStore(SimplePizzaFactory factory){
        this.factory = factory;
    }

    public Pizza orderPizza(String type){

        // 将具体类型的披萨委托给简单工厂生产
        Pizza pizza = factory.createPizza(type);

        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }

}

从上面可以看出,客户端不再创建具体的 CheesePizzaClamPizza 对象,创建的细节移到了工厂,如果披萨的类型增加了,或者创建过程发生了变化,都不需要修改客户端代码,只需要修改工厂就行了。

工厂方法模式

上面讲到的简单工厂将创建具体对象的过程剥离了出来,带来了很多优点,但是也有明显的缺点,假设要创建的类型很多的话,就需要在工厂类中写很多的判断条件,会导致庞大臃肿,每次增加或删除种类都需要打开工厂类进行修改,违背了开放-关闭原则。

工厂方法模式可以对简单工厂进一步解藕,解决上面的问题。

工厂方法模式定义了一个创建对象的接口,但是由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。

工厂方法模式是将简单工厂里面的多个类拆分到单个的工厂,也就是每一种类型都有自己的工厂子类(需要实现工厂“接口”),这样就避免了单个工厂类的臃肿问题,进一步降低了耦合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
 * 工厂接口,也可以是一个含有抽象方法的超类
 */
public interface Factory {

    /**
     * 必须含有创建对象的方法
     * @return
     */
    Pizza createPizza();

}

/**
 * 工厂子类,只创建CheesePizza
 */
public class CheesePizzaFactory implements Factory {

    @Override
    public Pizza createPizza() {
        return new CheesePizza();
    }

}

/**
 * 工厂子类,只创建ClamPizza
 */
public class ClamPizzaFactory implements Factory {

    @Override
    public Pizza createPizza() {
        return new ClamPizza();
    }

}

/**
 * 客户端
 */
public class PizzaStore2 {

    public Pizza orderPizza(){

        //需要什么类型,则创建对应的工厂类
        Factory factory = new CheesePizzaFactory();
        Pizza pizza = factory.createPizza();

        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }

}

工厂方法模式中,创建一种对象需要创建对应的工厂类,虽然将创建对象的细节剥离到了工厂类,但是这样在客户端中就需要new一个具体的工厂类了,虽然有办法避免这样的问题,但还是有些不理解,可能是应用的场景不同,上述例子并不是很合适。

###抽象工厂模式

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

看书给我的粗略理解是,按类型划分要创建的工厂(一类产品一个工厂)和产品(具体对象),首先定一个工厂接口,然后按类型实现工厂的子类,同时定义产品的接口,所有工厂产生的产品都需要实现产品的接口。抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的产品是什么,这样一来,客户端就从具体的产品中被解藕。结合书上的类图会更好理解一些。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/**
 * 工厂接口,也可以是一个含有抽象方法的超类
 */
public interface Factory {

    /**
     * 必须含有创建对象的方法
     * @return
     */
    Pizza createPizza(String type);

}

/**
 * 披萨接口,所有不同风格的披萨都需要实现此接口
 */
public interface Pizza {

    void bake();

    void cut();

    void box();

}

/**
 * 纽约风格披萨工厂类
 */
public class NyPizzaFactory implements Factory {

    @Override
    public Pizza createPizza(String type) {
        Pizza pizza;
        if (type.equals("cheesePizza")){
            // 创建纽约风格的芝士披萨
            pizza = new NyCheesePizza();
        }else {
            // 创建纽约风格的其他披萨
            pizza = new NyOtherPizza();
        }

        return pizza;
    }

}

/**
 * 披萨的具体实现,纽约风格的芝士披萨
 */
public class NyCheesePizza implements Pizza {

    @Override
    public void bake() {

    }

    @Override
    public void cut() {

    }

    @Override
    public void box() {

    }

}

/**
 * 客户端
 */
public class PizzaStore3 {

    public Pizza orderPizza(){

        //需要什么风格类型,则创建对应的工厂类
        Factory factory = new NyPizzaFactory();
        Pizza pizza = factory.createPizza("cheesePizza");

        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }

}

总结

看一遍书,对工厂模式有了大概是认识。简单工厂是一个工厂创建多种对象,将对象的创建细节剥离了出来,减少了客户端的依赖。工厂方法模式是更进一步将工厂拆分,一个工厂只生产一种产品,减少了单个工厂的臃肿。最后抽象工厂模式则是将产品和工厂都抽象到接口,客户端不关心具体调用的是哪个工厂,将得到什么产品,只需要制订好需要的产品类型就好了,这样就更加灵活了。