设计模式——工厂方法模式

精选推荐:设计模式——简单工厂设计模式——观察者模式设计模式——装饰者模式
所有的工厂模式都用来封装对象的创建。工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。
设计原则
依赖倒置原则
要依赖抽象,不要依赖具体类
定义
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
如同定义中所说的,工厂方法让子类决定要实例化的类是哪一个。所谓的“决定”,并不是指模式允许子类本身在运行时做决定,而是指在编写创建者类时,不需要知道实际创建的产品是哪一个。选择了使用哪个子类,自然就决定了实际创建的产品是什么。
类图

代码实现
我们还是以上面咖啡店为例。
一个大的咖啡店不可能只有一个,而是遍布在全国各地,上海、北京、深圳……都会有分店。而且如果经营的好,分店还会增加。
那么,每个地区的分店虽然都是售卖咖啡,但是为了满足各地区客户的需求偏好,也会根据当地特色有些许的不同。比如上海人喜欢吃甜的,那么上海分店可能生产出来的同样的咖啡味道为偏甜,北京人口味偏咸和鲜,讲究浓,那么同样的咖啡口味就会更浓,深圳属于南方,口味清淡,那可能就会是原味咖啡居多,不放牛奶也不放糖,浓淡适中……
对于咖啡厅,从制作好咖啡到送到客户手中还需要一系列步骤,比如打包……,而这个打包的过程程序就与咖啡的类别没有太大关系。
下面我们用代码来实现:
package com.study.design.Factory.factorymethod;
/**
 * 被生产对象的抽象父类
 */
public abstract class Coffe {
    protected String coffeName;
    public String getCoffeName() {
        return coffeName;
    }
}
package com.study.design.Factory.factorymethod;
public class SHLatteCoffe extends Coffe{
    public SHLatteCoffe(){
        coffeName = "shanghai latte";
    };
}
package com.study.design.Factory.factorymethod;
public class SHMochaCoffe extends Coffe{
    public SHMochaCoffe(){
        coffeName = "shanghai mocha";
    }
}
package com.study.design.Factory.factorymethod;
public class BJLatteCoffe extends Coffe{
    public BJLatteCoffe(){
        coffeName = "beijing latte";
    }
}
package com.study.design.Factory.factorymethod;
public class BJMochaCoffe extends Coffe{
    public BJMochaCoffe(){
        coffeName = "beijing mocha";
    }
}
package com.study.design.Factory.factorymethod;
public class SZLatteCoffe extends Coffe{
    public SZLatteCoffe(){
        coffeName = "shenzhen latte";
    }
}
package com.study.design.Factory.factorymethod;
public class SZMochaCoffe extends Coffe{
    public SZMochaCoffe(){
        coffeName = "shenzhen mocha";
    }
} 
package com.study.design.Factory.factorymethod;
/**
 * 咖啡店,现在它是个抽象类
 * 完成生产咖啡的所有工序,但是生产咖啡的具体口味由子类决定
 */
public abstract class CoffeStores {
    /**
     * 生产咖啡的工厂方法
     * @param type
     * @return
     */
    public Coffe productCoffe(int type){
        Coffe coffe = makeCoffe(type);
        box();
        return coffe;
    }
    /**
     * 打包
     */
    private void box(){
        System.out.println("packed……");
    }
    /**
     * 工厂方法
     * 生产咖啡的动作交由子类实现
     * @param type
     * @return
     */
    protected abstract Coffe makeCoffe(int type);
}
package com.study.design.Factory.factorymethod;
/**
 * 工厂类
 * 上海咖啡店
 */
public class SHCoffeStores extends BJCoffeStores {
    @Override
    protected Coffe makeCoffe(int type) {
        if (1 == type){
            return new SHMochaCoffe();
        }else{
            return new SHLatteCoffe();
        }
    }
}
package com.study.design.Factory.factorymethod;
public class BJCoffeStores extends CoffeStores{
    @Override
    protected Coffe makeCoffe(int type) {
        if (1 == type){
            return new BJMochaCoffe();
        }else {
            return new BJLatteCoffe();
        }
    }
}
package com.study.design.Factory.factorymethod;
public class SZCoffeStores extends CoffeStores{
    @Override
    protected Coffe makeCoffe(int type) {
        if (1 == type){
            return new SZMochaCoffe();
        }else{
            return new SZLatteCoffe();
        }
    }
}
package com.study.design.Factory.factorymethod;
public class SHConsumer {
    private CoffeStores coffeStores;
    public SHConsumer(CoffeStores coffeStores){
        this.coffeStores = coffeStores;
    }
    public void drink(int type){
        Coffe coffe = coffeStores.productCoffe(type);
        System.out.println("I got a cup of " + coffe.getCoffeName());
    }
}
package com.study.design.Factory.factorymethod;
public class BJConsumer {
    private CoffeStores coffeStores;
    public BJConsumer(CoffeStores coffeStores){
        this.coffeStores = coffeStores;
    }
    public void drink(int type){
        Coffe coffe = coffeStores.productCoffe(type);
        System.out.println("I got a cup of " + coffe.getCoffeName());
    }
}
package com.study.design.Factory.factorymethod;
public class SZConsumer {
    private CoffeStores coffeStores;
    public SZConsumer(CoffeStores coffeStores){
        this.coffeStores = coffeStores;
    }
    public void drink(int type){
        Coffe coffe = coffeStores.productCoffe(type);
        System.out.println("I got a cup of " + coffe.getCoffeName());
    }
}
package com.study.design.Factory.factorymethod;
public class FactoryMethodTest {
    public static void main(String[] args) {
        // 创建三个地区的咖啡厅实例
        SHCoffeStores shCoffeStores = new SHCoffeStores();
        BJCoffeStores bjCoffeStores = new BJCoffeStores();
        SZCoffeStores szCoffeStores = new SZCoffeStores();
        // 创建三个地区的消费者
        SHConsumer shConsumer = new SHConsumer(shCoffeStores);
        BJConsumer bjConsumer = new BJConsumer(bjCoffeStores);
        SZConsumer szConsumer = new SZConsumer(szCoffeStores);
        // 消费者消费各自地区的咖啡
        shConsumer.drink(1);
        bjConsumer.drink(2);
        szConsumer.drink(1);
    }
}
要点
- 所谓工厂方法,就是有一个方法起到工厂创建对象的作用。这个方法定义为抽象的,依赖子类处理对象的创建。而在父类中又可以定义一些所有对象通用的行为,比如打包……。
 - 每个抽象方法的具体实现子类,又可以看做是一个简单工厂。一般只负责创建实例对象。
 - 使用者通过选择不同的子类来获取不同的对象
 
简单工厂与工厂方法模式的区别:
简单工厂把全部的事情,在一个地方都处理完了,而工厂方法却是创建一个框架,让子类决定如何实现具体对象的创建。简单工厂可以将对象创建出来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。
当只有一个 SHCoffeStores 的时候,工厂方法模式有什么优点?
尽管只有一个具体创建者,工厂方法模式依然很有用,它帮助我们将产品的“实现”从“使用”中解耦。如果增加新的咖啡品种,CoffeStores 不会受到影响,因为 CoffeStores 与任何 SHCoffeStores 之间都不是紧耦合的。
