博客园不常在线

有问题联系微信

微信号

微信公众号

设计模式系列:创建型-工厂方法模式(Factory Method Pattern)

简介

工厂方法模式(Factory Method Pattern)是一种常用的创建型设计模式,它提供了一种创建对象的最佳方式。这种模式属于类创建型模式,是虚拟构造器(Virtual Constructor)模式或多态性工厂模式的别称。

在工厂方法模式中,定义一个用于创建对象的接口,让子类决定实例化哪一个类。父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。这种设计模式的目的是将类实例化操作延迟到子类中完成,即由子类来决定应该实例化哪个类。

使用工厂方法模式可以带来很多好处。首先,用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。其次,灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。此外,它是一种典型的解耦框架,高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。

在实际应用中,工厂方法模式可以用于各种需要创建对象的场景,例如创建数据库连接、网络连接、游戏对象等。通过使用工厂方法模式,可以将对象的创建和使用分离,提高代码的可维护性和可复用性。同时,它还可以降低系统的耦合度,使得系统更加灵活和可扩展。然而,过度使用工厂方法模式也可能会导致代码变得复杂和难以理解。因此,在使用时需要权衡利弊,合理运用。

结构

工厂方法模式的主要角色:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
  • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

案例实现

需求:设计一个咖啡店点餐系统。

设计一个咖啡类(Coffee),并定义其两个子类(美式咖啡【AmericanCoffee】和拿铁咖啡【LatteCoffee】);再设计一个咖啡店类(CoffeeStore),咖啡店具有点咖啡的功能。

具体类的设计如下:

image

在java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦,如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的;所以说,工厂模式最大的优点就是:解耦

使用工厂方法模式对上例进行改进,类图如下:

image

代码如下:

抽象工厂:

public interface CoffeeFactory {

    Coffee createCoffee();
}

具体工厂:

public class LatteCoffeeFactory implements CoffeeFactory {

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

public class AmericanCoffeeFactory implements CoffeeFactory {

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

咖啡店类:

public class CoffeeStore {

    private CoffeeFactory factory;

    public CoffeeStore(CoffeeFactory factory) {
        this.factory = factory;
    }

    public Coffee orderCoffee(String type) {
        Coffee coffee = factory.createCoffee();
        coffee.addMilk();
        coffee.addsugar();
        return coffee;
    }
}

从以上的编写的代码可以看到,要增加产品类时也要相应地增加工厂类,不需要修改工厂类的代码了,这样就解决了简单工厂模式的缺点。

工厂方法模式是简单工厂模式的进一步抽象。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。

优缺点

优点:

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

缺点:

  • 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

源码中的应用

JDK

java.util.Calendar 类

Java 中的 Calendar 类是用于操作日期和时间的类,它提供了一个静态工厂方法 getInstance(),用于获取 Calendar 对象的实例。根据不同的时区和区域设置,getInstance() 方法会返回一个 Calendar 对象的实例,而无需直接调用其构造函数。

Calendar calendar = Calendar.getInstance();

java.util.concurrent.Executors 类

Java 中的 Executors 类是用于创建线程池的工具类,它提供了一系列静态工厂方法来创建不同类型的线程池。例如,newFixedThreadPool() 方法用于创建固定大小的线程池,newCachedThreadPool() 方法用于创建根据需求创建新线程的线程池,等等。

ExecutorService executor = Executors.newFixedThreadPool(10);

java.util.regex.Pattern 类

Java 中的 Pattern 类表示一个正则表达式的编译结果。它提供了一个工厂方法 compile(),用于根据给定的正则表达式字符串创建一个 Pattern 对象的实例。compile() 方法根据指定的正则表达式字符串返回一个 Pattern 对象的实例。

Pattern pattern = Pattern.compile("regex");

java.nio.charset.Charset 类

Java 中的 Charset 类表示一个字符编码方案。它提供了一个工厂方法 forName(),用于根据字符编码名称获取 Charset 对象的实例。forName() 方法根据指定的字符编码名称返回一个 Charset 对象的实例。

Charset charset = Charset.forName("UTF-8");

Spring

BeanFactory 接口及其实现类

在 Spring 框架中,BeanFactory 接口是用于管理 Bean 对象的核心接口。它定义了一系列的工厂方法,用于创建和获取 Bean 对象的实例。Spring 框架提供了多种 BeanFactory 的实现类,如 XmlBeanFactory、DefaultListableBeanFactory 等,这些实现类通过工厂方法来创建和管理 Bean 对象。

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

ApplicationContext 接口及其实现类

在 Spring 框架中,ApplicationContext 接口是 BeanFactory 接口的扩展,它提供了更多的功能,如国际化、事件发布、AOP 等。ApplicationContext 接口也定义了一系列的工厂方法,用于创建和获取 Bean 对象的实例。Spring 框架提供了多种 ApplicationContext 的实现类,如 ClassPathXmlApplicationContext、AnnotationConfigApplicationContext 等。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

FactoryBean 接口及其实现类

在 Spring 框架中,FactoryBean 接口是一个特殊的工厂接口,用于创建特定类型的 Bean 对象。FactoryBean 接口定义了一个工厂方法 getObject(),用于创建 Bean 对象的实例。Spring 框架提供了多种 FactoryBean 的实现类,如 BeanFactory、ListableBeanFactory 等。

public class MyFactoryBean implements FactoryBean<MyBean> {
    @Override
    public MyBean getObject() throws Exception {
        // 创建并返回 MyBean 对象的实例
        return new MyBean();
    }
}
posted @ 2020-01-03 22:59  Code技术分享  阅读(116)  评论(0编辑  收藏  举报