设计模式-工厂方法模式

发布于:2024-04-18 ⋅ 阅读:(28) ⋅ 点赞:(0)

作者持续关注 WPS二次开发专题系列,持续为大家带来更多有价值的WPS二次开发技术细节,如果能够帮助到您,请帮忙来个一键三连,更多问题请联系我(QQ:250325397)

目录

定义

特点

使用场景

优缺点

(1) 优点

(2) 缺点

模式结构

具体实现

实际应用


定义

工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类创建型模式。

在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。

简单工厂模式违背了开闭原则,而“工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。

特点

定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

使用场景

    • 客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
    • 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
    • 客户不关心创建产品的细节,只关心产品的品牌

示例:

现在对该系统(简单工厂)进行修改,不再设计一个按钮工厂类来统一负责所有产品的创建,而是将具体按钮的创建过程交给专门的工厂子类去完成。

先定义一个抽象的按钮工厂类,再定义具体的工厂类来生成圆形按钮、矩形按钮、菱形按钮等,它们实现在抽象按钮工厂类中定义的方法。这种抽象化的结果使这种结构可以在不修改具体工厂类的情况下引进新的产品,如果出现新的按钮类型,只需要为这种新类型的按钮创建一个具体的工厂类就可以获得该新按钮的实例,这一特点无疑使得工厂方法模式具有超越简单工厂模式的优越性,更加符合“开闭原则”。

优缺点

(1) 优点
    • 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
    • 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
    • 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
(2) 缺点
    • 类的个数容易过多,增加复杂度
    • 增加了系统的抽象性和理解难度
    • 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。

模式结构

工厂方法模式包含如下角色:

  • Clickable:抽象产品,工厂方法模式所创建的对象的超类,也就是所有产品类的共同父类或共同拥有的接口。在实际的系统中,这个角色也常常使用抽象类实现。
  • CircleButton:具体产品,这个角色实现了抽象产品(Button)所声明的接口,工厂方法模式所创建的每一个对象都是某个具体产品的实例。
  • Factory:抽象工厂,担任这个角色的是工厂方法模式的核心,任何在模式中创建对象的工厂类必须实现这个接口。在实际的系统中,这个角色也常常使用抽象类实现。
  • CircleButtonFactory:具体工厂,担任这个角色的是实现了抽象工厂接口的具体Java类。具体工厂角色含有与业务密切相关的逻辑,并且受到使用者的调用以创建具体产品对象。

具体实现

产品接口和具体实现类:

/**
 * 产品接口--抽象按钮
 */
public interface Clickable {
    /**
     * 响应按钮点击
     */
    void onClick();
}

/**
 * 具体产品--圆形按钮
 */
public class CircleButton implements Clickable {
    @Override
    public void onClick() {
        System.out.println("button click: CircleButton...");
    }
}

工厂接口和具体产品工厂

/**
 * 工厂的抽象接口
 */
public interface Factory {

    /**
     * 创建按钮
     */
    Clickable createButton();
}

/**
 * 圆形按钮创建工厂
 */
public class CircleButtonFactory implements Factory {
    @Override
    public Clickable createButton() {
        System.out.println("CircleButton create factory...");
        return new CircleButton();
    }
}

具体使用

public class App {
    public static void main(String[] args) {
        //创建圆形按钮
        Factory factory = new CircleButtonFactory();
        Clickable circleButton = factory.createButton();
        System.out.println("button:" + circleButton);
        circleButton.onClick();

        //创建椭圆形按钮
        factory = new OvalButtonFactory();
        Clickable ovalButton = factory.createButton();
        System.out.println("button:" + ovalButton);
        ovalButton.onClick();

        //创建矩形按钮
        factory = new RectangleButtonFactory();
        Clickable rectangleButton = factory.createButton();
        System.out.println("button:" + rectangleButton);
        rectangleButton.onClick();
    }
}

实际应用

1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 日志记录类型:个人版日志记录器、海外版日志记录器,企业版日志记录器。

2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。

3、 设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。

4、 绘制对象创建器,各形状的绘制,播放动画等。