【设计模式】23种设计模式之工厂模式

工厂模式

​ 在现实生活中社会分工越来越细,越来越专业化。各种产品有专门的工厂生产,彻底告别了自给自足的小农经济时代,这大大缩短了产品的生产周期,提高了生产效率。同样,在软件开发中能否做到软件对象的生产和使用相分离呢?能否在满足“开闭原则”的前提下,客户随意增删或改变对软件相关对象的使用呢?这就是本节要讨论的问题。

定义

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

UML类图

【设计模式】23种设计模式之工厂模式_第1张图片

使用场景

1.客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。

2.创建产品的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。

3.客户不关心创建产品的细节,只关心产品的品牌。

示例

以下是工厂类:

Pizza工厂基类

/**
 * 产品工厂基类
 */
public abstract class PizzaFactory {

    /**
     * 根据Type创建不同的产品
     *
     * @param type 产品类型
     * @return
     */
    public Pizza createProduct(String type) {
        Pizza pizza;
        // 生产Pizza产品
        pizza = createPizza(type);
        // 对Pizza产品做一些操作
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        // 返回生产的产品
        return pizza;
    }

    protected abstract Pizza createPizza(String type);
}

纽约Pizza工厂

/**
 * 纽约Pizza工厂
 */
public class NYPizzaFactory extends PizzaFactory {
    @Override
    protected Pizza createPizza(String type) {
        Pizza pizza = null;
        switch (type) {
            case "Cheese":
                pizza = new NYStlyeCheesePizza();
                break;
            case "Clam":
                pizza = new NYStyleClamPizza();
                break;
        }
        return pizza;
    }
}

芝加哥Pizza工厂

/**
 * 芝加哥Pizza工厂
 */
public class ChicagoPizzaFactory extends PizzaFactory {

    @Override
    protected Pizza createPizza(String type) {
        Pizza pizza= null;
        switch (type){
            case "Cheese":
                pizza = new ChicagoCheesePizza();
                break;
            case "Clam":
                pizza = new ChicagoClamPizza();
                break;
        }
        return pizza;
    }
}

以下是产品类:

Pizza基类

/**
 * 披萨基类
 */
public class Pizza {
    protected String name; // 名称
    protected String dough; // 面团
    protected String sauce; // 酱料
    protected List<String> topping = new ArrayList(); // 配料

    public void prepare() {
        // 准备
        System.out.println("正在准备的Pizza:" + name);
    }

    public void bake() {
        // 烘培
        System.out.println("烘培需要30分钟..");
    }

    public void cut() {
        // 切片
        System.out.println("正在切片...");
    }

    public void box() {
        // 装盒
        System.out.println("Pizza装进方盒..");
    }

    public String getName() {
        return name;
    }
}

纽约奶酪Pizza

/**
 * 纽约奶酪Pizza
 */
public class NYStlyeCheesePizza extends Pizza {

    public NYStlyeCheesePizza(){
        name = "纽约奶酪Pizza";
        dough = "纽约面团";
        sauce  = "纽约酱料";
        topping.add("纽约佐料");
    }

    @Override
    public void cut(){
        System.out.println("纽约奶酪Pizza要切成圆形...");
    }
}

纽约蛤蜊Pizza

/**
 * 纽约蛤蜊Pizza
 */
public class NYStyleClamPizza extends Pizza {

    public NYStyleClamPizza(){
        name = "纽约蛤蜊Pizza";
        dough = "纽约面团";
        sauce  = "纽约酱料";
        topping.add("纽约佐料");
    }

    @Override
    public void cut(){
        System.out.println("纽约蛤蜊Pizza要切成圆形...");
    }
}

芝加哥奶酪Pizza

/**
 * 芝加哥奶酪Pizza
 */
public class ChicagoCheesePizza extends Pizza {
    public ChicagoCheesePizza(){
        name = "芝加哥奶酪Pizza";
        dough = "芝加哥面团";
        sauce  = "芝加哥酱料";
        topping.add("芝加哥佐料");
    }

    @Override
    public void cut(){
        System.out.println("芝加哥奶酪Pizza要切成方形...");
    }
}

芝加哥蛤蜊Pizza

/**
 * 芝加哥蛤蜊Pizza
 */
public class ChicagoClamPizza extends Pizza {

    public ChicagoClamPizza(){
        name = "芝加哥蛤蜊Pizza";
        dough = "芝加哥面团";
        sauce  = "芝加哥酱料";
        topping.add("芝加哥佐料");
    }

    @Override
    public void cut(){
        System.out.println("芝加哥蛤蜊Pizza要切成方形...");
    }
}

测试:

/**
 * 测试
 */
public class Test {
    public static void main(String[] args) {
        // 用纽约Pizza工厂生产一个纽约蛤蜊Pizza
        NYPizzaFactory nyPizzaFactory = new NYPizzaFactory();
        Pizza nyClamPizza = nyPizzaFactory.createProduct("Clam");

        // 用芝加哥Pizza工厂生产一个芝加哥奶酪Pizza
        ChicagoPizzaFactory chicagoPizzaFactory = new ChicagoPizzaFactory();
        Pizza chicagoCheesePizza = chicagoPizzaFactory.createProduct("Cheese");
    }
}

结果:

正在准备的Pizza:纽约蛤蜊Pizza
烘培需要30分钟..
纽约蛤蜊Pizza要切成圆形...
Pizza装进方盒..
正在准备的Pizza:芝加哥奶酪Pizza
烘培需要30分钟..
芝加哥奶酪Pizza要切成方形...
Pizza装进方盒..

优缺点

优点:

1.用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。

2.灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。

3.典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。

缺点:

1.类的个数容易过多,增加复杂度。

2.增加了系统的抽象性和理解难度。

3.抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。

工作中的应用

敬请期待

设计原则工具箱

1.找出应用中可能需要变化的部分,把它们独立出来,不要和那些不需要变化的代码混合在一起

2.针对接口(超类型)编程而不是针对具体的实现编程

3.多用组合少用继承

4.为了交互对象之间的松耦合设计而努力

5.类应该对扩展开放,对修改关闭

6.依赖抽象,不要依赖具体类。(即不要让高层组件依赖低层组件,而且不管高层组件还是低层组件都应该依赖于抽象)

你可能感兴趣的:(java,设计模式,java,抽象工厂模式)