设计模式学习总结——工厂模式

简介: 在我们平常创建对象的时候,都是通过关键字 new 来实现的,例: Class A = new A() 。在一些情况下,要创建的对象需要一系列复杂的初始化操作,比如查配置文件、查数据库表、初始化成员对象等,如果把这些逻辑放在构造函数中,会极大影响代码的可读性。不妨定义一个类来专门负责对象的创建,这样的类就是工厂类,这种做法就是工厂模式,在任何需要生成复杂对象的地方,都可以使用工厂模式。工厂模式包括:简单工厂(不在23种设计模式中)、工厂方法和抽象工厂。

原创 房辉(怀兴) 淘系技术  2020-12-02


解决的问题



客户端在调用时不想判断来实例化哪一个类或者实例化的过程过于复杂。


在工厂模式中,具体的实现类创建过程对客户端是透明的,客户端不决定具体实例化哪一个类,而是交由“工厂”来实例化。



简单工厂



 结构


定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类。

image.png


  • 抽象类或接口:定义了要创建的产品对象的接口。
  • 具体实现:具有统一父类的具体类型的产品。
  • 产品工厂:负责创建产品对象。工厂模式同样体现了开闭原则,将“创建具体的产品实现类”这部分变化的代码从不变化的代码“使用产品”中分离出来,之后想要新增产品时,只需要扩展工厂的实现即可。

使用


创建不同品牌的键盘


public interface Keyboard {
    void print();
    void input(Context context);
}
class HPKeyboard implements Keyboard {
    @Override
    public void print() {
        //...输出逻辑;
    }
    @Override
    public void input(Context context) {
        //...输入逻辑;
    }
}
class DellKeyboard implements Keyboard {
    @Override
    public void print() {
        //...输出逻辑;
    }
    @Override
    public void input(Context context) {
        //...输入逻辑;
    }
}
class LenovoKeyboard implements Keyboard {
    @Override
    public void print() {
        //...输出逻辑;
    }
    @Override
    public void input(Context context) {
        //...输入逻辑;
    }
}
/**
 * 工厂
 */
public class KeyboardFactory {
    public Keyboard getInstance(int brand) {
        if(BrandEnum.HP.getCode() == brand){
            return new HPKeyboard();
        } else if(BrandEnum.LENOVO.getCode() == brand){
            return new LenovoKeyboard();
        } else if(BrandEnum.DELL.getCode() == brand){
            return new DellKeyboard();
        }
        return null;
    }
    public static void main(String[] args) {
        KeyboardFactory keyboardFactory = new KeyboardFactory();
        Keyboard lenovoKeyboard = KeyboardFactory.getInstance(BrandEnum.LENOVO.getCode());
        //...
    }
}


 缺陷


上面的工厂实现是一个具体的类KeyboardFactory,而非接口或者抽象类,getInstance()方法利用if-else创建并返回具体的键盘实例,如果增加新的键盘子类,键盘工厂的创建方法中就要增加新的if-else。这种做法扩展性差,违背了开闭原则,也影响了可读性。所以,这种方式使用在业务较简单,工厂类不会经常更改的情况。


工厂方法


为了解决上面提到的"增加if-else"的问题,可以为每一个键盘子类建立一个对应的工厂子类,这些工厂子类实现同一个抽象工厂接口。这样,创建不同品牌的键盘,只需要实现不同的工厂子类。当有新品牌加入时,新建具体工厂继承抽象工厂,而不用修改任何一个类。


 结构


image.png


  • 抽象工厂:声明了工厂方法的接口。
  • 具体产品工厂:实现工厂方法的接口,负责创建产品对象。
  • 产品抽象类或接口:定义工厂方法所创建的产品对象的接口。
  • 具体产品实现:具有统一父类的具体类型的产品。


 使用


public interface IKeyboardFactory {
    Keyboard getInstance();
}
public class HPKeyboardFactory implements IKeyboardFactory {
    @Override
    public Keyboard getInstance(){
        return new HPKeyboard();
    }
}
public class LenovoFactory implements IKeyboardFactory {
    @Override
    public Keyboard getInstance(){
        return new LenovoKeyboard();
    }
}
public class DellKeyboardFactory implements IKeyboardFactory {
    @Override
    public Keyboard getInstance(){
        return new DellKeyboard();
    }
}


 缺点


每一种品牌对应一个工厂子类,在创建具体键盘对象时,实例化不同的工厂子类。但是,如果业务涉及的子类越来越多,难道每一个子类都要对应一个工厂类吗?这样会使得系统中类的个数成倍增加,增加了代码的复杂度。



抽象工厂


为了缩减工厂实现子类的数量,不必给每一个产品分配一个工厂类,可以将产品进行分组,每组中的不同产品由同一个工厂类的不同方法来创建。


例如,键盘、主机这2种产品可以分到同一个分组——电脑,而不同品牌的电脑由不同的制造商工厂来创建。

image.png


类似这种把产品类分组,组内不同产品由同一工厂类的不同方法实现的设计模式,就是抽象工厂模式。


抽象工厂适用于以下情况:


1. 一个系统要独立于它的产品的创建、组合和表示时;
2. 一个系统要由多个产品系列中的一个来配置时;
3. 要强调一系列相关的产品对象的设计以便进行联合使用时;
4. 当你提供一个产品类库,而只想显示它们的接口而不是实现时;


 结构


image.png


  • 抽象工厂:声明了创建抽象产品对象的操作接口。
  • 具体产品工厂:实现了抽象工厂的接口,负责创建产品对象。
  • 产品抽象类或接口:定义一类产品对象的接口。
  • 具体产品实现:定义一个将被相应具体工厂创建的产品对象。

 使用


public interface Keyboard {
   void print();
}
public class DellKeyboard implements Keyboard {
    @Override
    public void print() {
        //...dell...dell;
    }
}
public class HPKeyboard implements Keyboard {
    @Override
    public void print() {
        //...HP...HP;
    }
}
public interface Monitor {
   void play();
}
public class DellMonitor implements Monitor {
    @Override
    public void play() {
        //...dell...dell;
    }
}
public class HPMonitor implements Monitor {
    @Override
    public void play() {
        //...HP...HP;
    }
}
public interface MainFrame {
   void run();
}
public class DellMainFrame implements MainFrame {
    @Override
    public void run() {
        //...dell...dell;
    }
}
public class HPMainFrame implements MainFrame {
    @Override
    public void run() {
        //...HP...HP;
    }
}
//工厂类。工厂分为Dell工厂和HP工厂,各自负责品牌内产品的创建
public interface IFactory {
    MainFrame createMainFrame();
    Monitor createMainFrame();
    Keyboard createKeyboard();
}
public class DellFactory implements IFactory {
      @Override
      public MainFrame createMainFrame(){
                MainFrame mainFrame = new DellMainFrame();
             //...造一个Dell主机;
             return mainFrame;
      }
      @Override
      public Monitor createMonitor(){
                Monitor monitor = new DellMonitor();
             //...造一个Dell显示器;
             return monitor;
      }
      @Override
      public Keyboard createKeyboard(){
                Keyboard keyboard = new DellKeyboard();
             //...造一个Dell键盘;
             return Keyboard;
      }
}
public class HPFactory implements IFactory {
      @Override
      public MainFrame createMainFrame(){
                MainFrame mainFrame = new HPMainFrame();
             //...造一个HP主机;
             return mainFrame;
      }
      @Override
      public Monitor createMonitor(){
                Monitor monitor = new HPMonitor();
             //...造一个HP显示器;
             return monitor;
      }
      @Override
      public Keyboard createKeyboard(){
                Keyboard keyboard = new HPKeyboard();
             //...造一个HP键盘;
             return Keyboard;
      }
}
//客户端代码。实例化不同的工厂子类,可以通过不同的创建方法创建不同的产品
public class Main {
    public static void main(String[] args) {
        IFactory dellFactory = new DellFactory();
        IFactory HPFactory = new HPFactory();
        //创建戴尔键盘
        Keyboard dellKeyboard = dellFactory.createKeyboard();
        //...
    }
}


 优缺点


增加分组非常简单,例如要增加Lenovo分组,只需创建Lenovo工厂和具体的产品实现类。分组中的产品扩展非常困难,要增加一个鼠标Mouse,既要创建抽象的Mouse接口, 又要增加具体的实现:DellMouse、HPMouse, 还要再每个Factory中定义创建鼠标的方法实现。


 总结


  • 简单工厂:唯一工厂类,一个产品抽象类,工厂类的创建方法依据入参判断并创建具体产品对象。
  • 工厂方法:多个工厂类,一个产品抽象类,利用多态创建不同的产品对象,避免了大量的if-else判断。
  • 抽象工厂:多个工厂类,多个产品抽象类,产品子类分组,同一个工厂实现类创建同组中的不同产品,减少了工厂子类的数量。


在下述情况下可以考虑使用工厂模式:


  1. 在编码时不能预见需要创建哪种类的实例。
  2. 系统不应依赖于产品类实例如何被创建、组合和表达的细节。


总之,工厂模式就是为了方便创建同一接口定义的具有复杂参数和初始化步骤的不同对象。工厂模式一般用来创建复杂对象。只需用new就可以创建成功的简单对象,无需使用工厂模式,否则会增加系统的复杂度。


此外,如果对象的参数是不固定的,推荐使用Builder模式。


后记



在实际项目中,结合Spring中的InitializingBean接口,可以利用@Autowired注解优雅的实现工厂。

相关文章
|
1月前
|
设计模式 Java
【设计模式】工厂模式(定义 | 特点 | Demo入门讲解)
【设计模式】工厂模式(定义 | 特点 | Demo入门讲解)
53 2
|
5月前
|
设计模式
**工厂模式与抽象工厂模式**都是创建型设计模式,用于封装对象创建,减少耦合
【6月更文挑战第23天】**工厂模式与抽象工厂模式**都是创建型设计模式,用于封装对象创建,减少耦合。工厂模式专注于单个对象,通过具体工厂创建具体产品,适用于简单对象创建;抽象工厂则关注一系列相关产品,提供创建一族对象的接口,适用于处理多个不兼容产品族。选择模式基于问题域的复杂性,单个产品需求时用工厂模式,多产品族时用抽象工厂模式。
33 5
|
6月前
|
设计模式 Java
Java一分钟之-设计模式:工厂模式与抽象工厂模式
【5月更文挑战第17天】本文探讨了软件工程中的两种创建型设计模式——工厂模式和抽象工厂模式。工厂模式提供了一个创建对象的接口,延迟实例化到子类决定。过度使用或违反单一职责原则可能导致问题。代码示例展示了如何创建形状的工厂。抽象工厂模式则用于创建一系列相关对象,而不指定具体类,但添加新产品可能需修改现有工厂。代码示例展示了创建颜色和形状的工厂。根据需求选择模式,注意灵活性和耦合度。理解并恰当运用这些模式能提升代码质量。
63 2
|
2月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
3月前
|
设计模式 Java
Java 设计模式之谜:工厂模式与抽象工厂模式究竟隐藏着怎样的神奇力量?
【8月更文挑战第30天】在Java编程中,设计模式为常见问题提供了高效解决方案。工厂模式与抽象工厂模式是常用的对象创建型设计模式,能显著提升代码的灵活性、可维护性和可扩展性。工厂模式通过定义创建对象的接口让子类决定实例化哪个类;而抽象工厂模式则进一步提供了一个创建一系列相关或相互依赖对象的接口,无需指定具体类。这种方式使得系统更易于扩展和维护。
42 1
|
3月前
|
设计模式 算法 开发者
深入理解工厂模式与策略模式:设计模式的灵活应用
深入理解工厂模式与策略模式:设计模式的灵活应用
|
3月前
|
设计模式 uml C语言
设计模式----------工厂模式之简单工厂模式(创建型)
这篇文章详细介绍了简单工厂模式,包括其定义、应用场景、UML类图、通用代码实现、运行结果、实际应用例子,以及如何通过反射机制实现对象创建,从而提高代码的扩展性和维护性。
设计模式----------工厂模式之简单工厂模式(创建型)
|
3月前
|
设计模式 uml
设计模式-------------工厂模式之工厂方法模式(创建型)
工厂方法模式是一种创建型设计模式,它通过定义一个用于创建对象的接口,让子类决定实例化哪一个类,从而实现类的实例化推迟到子类中进行,提高了系统的灵活性和可扩展性。
|
3月前
|
设计模式 Java C语言
设计模式-----------工厂模式之抽象工厂模式(创建型)
抽象工厂模式是一种创建型设计模式,它提供了一个接口用于创建一系列相关或相互依赖的对象,而无需指定具体类,从而增强了程序的可扩展性并确保客户端只使用同一产品族的产品。
设计模式-----------工厂模式之抽象工厂模式(创建型)
|
4月前
|
设计模式 C++
C++一分钟之-设计模式:工厂模式与抽象工厂
【7月更文挑战第14天】设计模式是解决软件设计问题的通用方案。工厂模式与抽象工厂模式是创建型模式,用于对象创建而不暴露创建逻辑。工厂模式推迟实例化到子类,但过度使用会增加复杂性。抽象工厂则创建相关对象族,但过度抽象可能造成不必要的复杂度。两者均应按需使用,确保设计灵活性。代码示例展示了C++中如何实现这两种模式。
43 3

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    43
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    48
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    58
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    63
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    58
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    42
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    110
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78
  • 下一篇
    无影云桌面