Bootstrap

设计模式——工厂模式

前言

传统模式创建的优缺点

  1. 优点是比较好理解,简单易操作。
  2. 缺点是违反了设计模式的 ocp 原则,即对扩展开放,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码
  3. 比如我们这时要新增加一个新的实现类,需要修改源代码

现有3个类,分别是Coffee、AmericanCoffee、LatteCoffee

  • Coffee类
public class Coffee {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void addSugar(){
        System.out.println("Coffee加糖");
    }

    public void addMilk(){
        System.out.println("Coffee加奶");
    }
}
  • AmericanCoffee
public class AmericanCoffee extends Coffee {

    @Override
    public void addSugar(){
        System.out.println("AmericanCoffee加糖");
    }

    @Override
    public void addMilk(){
        System.out.println("AmericanCoffee加奶");
    }
}
  • LatteCoffee
public class LatteCoffee extends Coffee {

    @Override
    public void addSugar(){
        System.out.println("LatteCoffee加糖");
    }

    @Override
    public void addMilk(){
        System.out.println("LatteCoffee加奶");
    }
}

1.简单工厂模式

简单工厂模式不是一个正式的设计模式,但它是工厂模式的基础。
它使用一个单独的工厂类来创建不同的对象,根据参数类型决定创建哪种类型的对象。

1.1 简单介绍

  1. 简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
  2. 简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
  3. 在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式

1.2 代码实现

public class SimpleCoffeeFactory {

    public Coffee createCoffee(String type){
        Coffee coffee = null;
        if ("american".equals(type)) {
            return new AmericanCoffee();
        } else if ("latte".equals(type)) {
            return new LatteCoffee();
        }
        return coffee;
    }

}

这样每次创建只需要根据type来判断就行了,而且如果你新增了一个子类(浓缩咖啡)也不用去修改父类的代码,只需要修改工厂的代码即可

public class SimpleCoffeeFactory {

    public Coffee createCoffee(String type){
        Coffee coffee = null;
        if ("american".equals(type)) {
            return new AmericanCoffee();
        } else if ("latte".equals(type)) {
            return new LatteCoffee();
        } else if ("nongsuo".equals(type)){
            return NongSuoCoffee();
        }
        return coffee;
    }

}

1.3 优缺点

  1. 封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。
  2. 增加新产品时还是需要修改工厂类的代码,违背了“开闭原则"

2.工厂方法模式

2.1 简单介绍

  1. 工厂方法模式设计方案:将实例化功能抽象成抽象方法,根据不同的类型实例化子类。
  2. 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例

2.2 代码实现

  1. 需要一个咖啡工厂
public interface CoffeeFactory {
    Coffee createCoffee();
}
  1. 美式咖啡工厂
public class AmericanCoffeeFactory implements CoffeeFactory {

    public Coffee createCoffee() {
        return new AmericanCoffee();
    }
}
  1. 拿铁咖啡工厂
public class LatteCoffeeFactory implements CoffeeFactory {

    public Coffee createCoffee() {
        return new LatteCoffee();
    }
}

同样,如果你需要添加一个浓缩咖啡,只需要创建一个浓缩咖啡工厂的实现类,来实现咖啡工厂,通过Java的多态来创建想要的咖啡对象

2.3 优缺点

  1. 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改满足开闭原则;
  2. 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

3.抽象工厂模式

3.1 简单介绍

  1. 抽象工厂模式:定义了一个interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类
  2. 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
  3. 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。
  4. 将工厂抽象成两层,AbsFactory(抽象工厂)和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。

3.2 代码实现

现有需求添加甜品,那么咖啡工厂就不够用了,所以这个时候我们往上套一个工厂,既可以创建咖啡,又可以创建甜品

public interface DessertFactory {
    Coffee createCoffee();
    Dessert createDessert();
}


public class ItalyDessertFactory implements DessertFactory {

    public Coffee createCoffee() {
        return new LatteCoffee();
    }

    public Dessert createDessert() {
        return new Tiramisu();
    }
}

public class AmericanDessertFactory implements DessertFactory {

    public Coffee createCoffee() {
        return new AmericanCoffee();
    }

    public Dessert createDessert(){
        return new MatchaMousse();
    }
}

3.3 优缺点

  1. 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象.
  2. 当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。

总结

工厂模式的意义
将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。

  1. 三种工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)
  2. 设计模式的依赖抽象原则
  • 创建对象实例时,不要直接 new 类,而是把这个new 类的动作放在一个工厂的方法中,并返回。有的书上说变量不要直接持有具体类的引用。
  • 不要让类继承具体类,而是继承抽象类或者是实现interface(接口)
  • 不要覆盖基类中已经实现的方法。

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;