工厂模式(Factory Pattern)

115 阅读8分钟

攻略大全

1. 粘贴攻略

2. 造火箭攻略

3. 拧螺丝攻略

3.1 简单工厂模式(Simple Factory Pattern)

/**
 * @author Renzituo
 * time: 2022/11/15 22:36
 * desc: 产品抽象接口,描述产品的公共接口
 */
public interface IAnimalProduct {

    /**
     * 可定义所有产品的抽象行为
     */

    void doSomething();

}
/**
 * @author Renzituo
 * time: 2022/11/15 22:40
 * desc: 具体产品,猫
 */
public class CatProduct implements IAnimalProduct{
    @Override
    public void doSomething() {
        System.out.println("CatProduct");
    }
}
/**
 * @author Renzituo
 * time: 2022/11/15 22:40
 * desc: 具体产品,狗
 */
public class DogProduct implements IAnimalProduct{
    @Override
    public void doSomething() {
        System.out.println("DogProduct");
    }
}
/**
 * @author Renzituo
 * time: 2022/11/15 22:40
 * desc: 具体产品,人
 */
public class PersonProduct implements IAnimalProduct{
    @Override
    public void doSomething() {
        System.out.println("PersonProduct");
    }
}
/**
 * @author Renzituo
 * time: 2022/11/15 22:38
 * desc: 产品工厂:被外界调用,根据传入不同参数从而创建不同具体产品类的实例
 *
 *
 *      简单工厂模式
 *      优点:将创建实例的工作与使用实例的工作分开,使用者不必关心类对象如何创建,实现了解耦;
 *      把初始化实例时的工作放到工厂里进行,使代码更容易维护。 更符合面向对象的原则 & 面向接口编程,而不是面向实现编程。
 *
 *      缺点:工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响;
 *      违背“开放 - 关闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂;
 *      简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构。
 *
 *      应用场景:客户如果只知道传入工厂类的参数,对于如何创建对象的逻辑不关心时;当工厂类负责创建的对象(具体产品)比较少时。
 *
 */
class AnimalFactory {

    /**
     * 工厂类里使用switch语句控制生产哪种商品
     * 使调用者只需要调用工厂的静态方法就可以实现产品类的实例化
     * @param productName
     * @return
     */
    public static IAnimalProduct create(String productName) {

        switch (productName) {
            case "cat":
                return new CatProduct();
            case "dog":
                return new DogProduct();
            default:
                return null;
        }

    }
}

3.2 工厂方法模式(Factory Method Pattern)

/**
 * @author Huadao
 * @date Created in 2022/11/16
 * @desc 抽象工厂:描述具体工厂的公共接口
 */
public interface IAnimalFactory {

    IAnimalProduct createAnimal();

}
/**
 * @author Huadao
 * @date Created in 2022/11/16
 * @desc 具体工厂类,由外界直接调用进而生产
 */
public class CatFactory implements IAnimalFactory{

    /**
     * 通过具体工厂创建对应的产品
     * @return
     */
    @Override
    public IAnimalProduct createAnimal() {
        return new CatProduct();
    }
}
/**
 * @author Huadao
 * @date Created in 2022/11/16
 * @desc 具体工厂,由外界直接调用进而生产
 */
public class DogFactory implements IAnimalFactory{

    /**
     * 通过具体工厂创建对应的产品
     * @return
     */
    @Override
    public IAnimalProduct createAnimal() {
        return new DogProduct();
    }
}

3.2.1 优点

  • 更符合开-闭原则
    • 新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可
    • 简单工厂模式需要修改工厂类的判断逻辑
  • 符合单一职责原则
    • 每个具体工厂类只负责创建对应的产品
    • 简单工厂中的工厂类存在复杂的switch逻辑判断
  • 不使用静态工厂方法,可以形成基于继承的等级结构
    • 简单工厂模式的工厂类使用静态工厂方法

总结:工厂方法模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。

3.2.2 缺点

  • 添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;

  • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

  • 虽然保证了工厂方法内的对外修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;

  • 一个具体工厂只能创建一种具体产品

3.2.3 使用场景

  • 当一个类不知道它所需要的对象的类时
    在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可;

  • 当一个类希望通过其子类来指定创建对象时
    在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。

  • 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

3.3 抽象工厂模式(Abstract Factory Pattern)

3.3.1 抽象工厂类

/**
 * @author Huadao
 * @date Created in 2022/11/16
 * @desc 抽象工厂:描述具体工厂的公共接口
 */
public interface IAnimalFactory {

    IAnimal createAnimal();

    IAnimal createAnimalFood();

}

3.3.2 抽象产品族

/**
 * @author Huadao
 * @date Created in 2022/11/16
 * @desc 抽象产品族,抽象产品的父类,描述抽象产品的公共接口
 */
public abstract class IAnimal {

    public abstract void doSomething();
}

3.3.3 抽象产品类

/**
 * @author Huadao
 * @date Created in 2022/11/16
 * @desc 抽象产品,具体产品的父类,描述具体产品的公共接口
 */
public abstract class IAnimalProduct extends IAnimal{

}
/**
 * @author Huadao
 * @date Created in 2022/11/16
 * @desc 抽象产品,具体产品的父类,描述具体产品的公共接口
 */
public abstract class IAnimalFoodProduct extends IAnimal {

}

3.3.4 具体产品类

/**
 * @author Huadao
 * @date Created in 2022/11/16
 * @desc
 */
public class CatProduct extends IAnimalProduct{
    @Override
    public void doSomething() {
        System.out.println("CatProduct");
    }
}
/**
 * @author Huadao
 * @date Created in 2022/11/16
 * @desc
 */
public class DogProduct extends IAnimalProduct{
    @Override
    public void doSomething() {
        System.out.println("DogProduct");
    }
}
/**
 * @author Huadao
 * @date Created in 2022/11/16
 * @desc
 */
public class CatFoodProduct extends IAnimalFoodProduct{

    @Override
    public void doSomething() {
        System.out.println("CatFoodProduct");
    }
}
/**
 * @author Huadao
 * @date Created in 2022/11/16
 * @desc 具体产品,抽象产品的子类,工厂类的创建目标类,描述生产的具体产品
 */
public class DogFoodProduct extends IAnimalFoodProduct{
    @Override
    public void doSomething() {
        System.out.println("DogProduct");
    }
}

3.3.5 具体工厂类

/**
 * @author Huadao
 * @date Created in 2022/11/16
 * @desc 具体工厂
 */
public class CatFactory implements IAnimalFactory{

    /**
     * 通过具体工厂创建对应的产品
     * @return
     */
    @Override
    public IAnimalProduct createAnimal() {
        // 生产狗
        return new CatProduct();
    }

    @Override
    public IAnimalFoodProduct createAnimalFood() {
        // 生产猫粮
        return new CatFoodProduct();
    }
}
/**
 * @author Huadao
 * @date Created in 2022/11/16
 * @desc 具体工厂
 */
public class DogFactory implements IAnimalFactory{

    /**
     * 通过具体工厂创建对应的产品
     * @return
     */
    @Override
    public IAnimalProduct createAnimal() {
        // 生产狗
        return new DogProduct();
    }

    @Override
    public IAnimalFoodProduct createAnimalFood() {
        // 生产狗粮
        return new DogFoodProduct();
    }
}

3.3.6 优点

  • 降低耦合
    抽象工厂模式将具体产品的创建延迟到具体工厂的子类中,这样将对象的创建封装起来,可以减少客户端与具体产品类之间的依赖,从而使系统耦合度低,这样更有利于后期的维护和扩展;
  • 更符合开-闭原则
    新增一种产品类时,只需要增加相应的具体产品类和相应的工厂子类即可

简单工厂模式需要修改工厂类的判断逻辑

  • 符合单一职责原则
    每个具体工厂类只负责创建对应的产品

简单工厂中的工厂类存在复杂的switch逻辑判断

  • 不使用静态工厂方法,可以形成基于继承的等级结构。

简单工厂模式的工厂类使用静态工厂方法

3.3.7 缺点

抽象工厂模式很难支持新种类产品的变化。
这是因为抽象工厂接口中已经确定了可以被创建的产品集合,如果需要添加新产品,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类以及所有子类的改变,这样也就违背了“开发——封闭”原则。

对于旧的产品族符合开-闭原则;对于新的产品种类不符合开-闭原则,这一特性称为开-闭原则的倾斜性。

3.3.8 应用场景

  • 一个系统不要求依赖产品类实例如何被创建、组合和表达的表达,这点也是所有工厂模式应用的前提。

  • 这个系统有多个系列产品,而系统中只消费其中某一系列产品

  • 系统要求提供一个产品类的库,所有产品以同样的接口出现,客户端不需要依赖具体实现。

4. 复制攻略

4.1 Carson带你学设计模式:这是一份全面 & 详细的设计模式学习指南