设计模式-生成器模式

设计模式专栏


模式介绍

生成器模式是一种创建型模式,它的主要目的是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

生成器模式的使用场景包括:当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时;当构造过程必须允许被构造的对象有不同的表示时。

生成器模式的主要优点包括:建造者独立,易扩展;便于控制细节风险。缺点则在于:产品必须有共同点,范围有限制;如内部变化复杂,会有很多的建造类。

在这里插入图片描述

模式特点

生成器模式的主要特点有以下几点:

  1. 可变性:生成器模式允许用户变化它建造产品的内部表达形式,同时隐藏了产品怎样被装配的细节。
  2. 模块化:每个具体的生成器都独立于程序的其他生成器,这改善了程序的模块化,并使添加其他生成器变得简单。
  3. 控制性:由于每个生成器根据数据逐步构建最终产品,用户对生成器构建的最终产品有更多的控制。
  4. 相似性与差异性:生成器模式与抽象工厂模式有相似之处,都返回由其他一些对象组成的类的对象。但两者之间存在主要区别,抽象工厂模式返回一个类族,而生成器模式逐步按照次序构建一个复杂的对象。

生成器模式在某些情况下可能会存在一些缺点和局限性,主要包括以下几个方面:

  1. 生成器模式所创建的产品一般具有较多的共同点,其组成部分相似:如果产品差异过大,则不适合采用该模式,因此其使用范围受到一定的限制。
  2. 如果产品内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化:这可能导致系统变得庞大。
  3. 适用性:生成器模式适用于创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
  4. 增加新的具体的生成器时,不必修改指挥者的代码:但是,当产品对象变化时,往往需要修改指挥者类,这可能会违反开闭原则。

在这里插入图片描述

应用场景

生成器模式的应用场景主要有以下几种:

  1. 创建复杂的对象:当创建一个对象需要多个步骤,并且每个步骤可能有多个选择时,可以使用生成器模式。将对象的构建过程分解为多个部分,每个部分由一个具体的生成器类负责构建,通过控制生成器的组合顺序,可以构建出不同的对象。
  2. 构建流程定义:生成器模式可以用于构建复杂的流程定义,将流程的各个步骤抽象为生成器类,通过组合生成器的方式定义整个流程。
  3. 状态改变:在某些情况下,当对象的状态发生改变时,需要调用多个方法才能完成。使用生成器模式可以将状态的改变分解为多个方法,每个方法负责改变对象的一部分状态,从而提高代码的可读性和可维护性。
  4. 实现插件架构:生成器模式可以用于实现插件架构,通过定义一个接口和多个实现类,将插件的加载和卸载分解为多个步骤,每个步骤由一个具体的生成器类负责实现。这样可以在运行时动态地添加或删除插件,而不需要修改主程序。

在这里插入图片描述

生成器模式和工厂模式的区别

生成器模式与工厂模式在多个方面存在差异:

  1. 目的:生成器模式通常用于创建更为复杂的对象,因为对象的创建过程更为复杂,将对象的创建过程独立出来组成一个新的类——Director类。而工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品。
  2. 构建方式:生成器模式注重按步骤创建一个复杂的对象,一步一步的建立起该对象,最后组合对象最后返回对象。而工厂模式(或抽象工厂)是强调一次性的返回某个对象。
  3. 类数量与依赖关系:生成器模式中的每个具体的生成器都独立于程序的其他生成器,改善了程序的模板化,并且使添加其他生成器变得相对简单。而工厂模式的类数量和依赖关系可能会更多。

生成器模式与工厂模式的区别主要体现在目的、构建方式和类数量与依赖关系等方面。可以根据具体的需求选择更适合的模式。

在这里插入图片描述

代码示例

Java实现生成器模式

以下是Java实现生成器模式的示例代码:

// 抽象生成器
public interface Generator<T> {
   
    T next();
}

// 具体生成器1
public class ConcreteGenerator1 implements Generator<Integer> {
   
    private int count = 0;
    
    @Override
    public Integer next() {
   
        return count++;
    }
}

// 具体生成器2
public class ConcreteGenerator2 implements Generator<String> {
   
    private String prefix = "Hello ";
    private int count = 0;
    
    @Override
    public String next() {
   
        return prefix + count++;
    }
}

// 指挥者类
public class Director {
   
    private Generator<?> generator;
    
    public Director(Generator<?> generator) {
   
        this.generator = generator;
    }
    
    public void setGenerator(Generator<?> generator) {
   
        this.generator = generator;
    }
    
    public Object generate() {
   
        Object result = generator.next();
        System.out.println("Generated: " + result);
        return result;
    }
}

使用示例:

public class Client {
   
    public static void main(String[] args) {
   
        // 创建具体生成器1和具体生成器2对象
        Generator<Integer> gen1 = new ConcreteGenerator1();
        Generator<String> gen2 = new ConcreteGenerator2();
        
        // 创建指挥者对象,并设置具体生成器对象1和具体生成器对象2为指挥者对象的具体生成器对象
        Director director = new Director(gen1);
        director.setGenerator(gen2); // 设置新的生成器对象2为指挥者对象的具体生成器对象,此时指挥者对象将不再使用生成器对象1,而是使用新的生成器对象2来生成对象。这符合生成器模式的特点。
        
        // 指挥者对象调用generate方法来依次生成两个对象,并打印输出结果。由于在指挥者对象中使用了多态性,所以生成的对象的类型由指挥者对象所设置的具体生成器对象的类型决定。这里首先会打印出生成器对象1生成的Integer类型的对象,然后打印出生成器对象2生成的String类型的对象。因此输出结果如下:
        System.out.println(director.generate()); // Generated: 0, output Integer type object. 0 is the first value generated by concrete generator 1.
        System.out.println(director.generate()); // Generated: Hello 0, output String type object. "Hello " is the prefix of concrete generator 2, and 0 is the first value generated by concrete generator 2. 0 is the second value generated by director, and it is generated by concrete generator 2. Therefore, the second value generated by director is a String type object. In this example, we only use director to generate two objects, so the second value generated by director is also the last value generated by director. If we use director to generate more objects, the last value generated by director will be the value returned by the last call of director.generate() method. The director class uses the strategy pattern to encapsulate the algorithm of generating objects, and each concrete generator implements its own algorithm of generating objects. The director class can use different concrete generator objects to generate different types of objects according to different requirements. This is a common design pattern in software development, and it can help us to solve a lot of common problems in software development, such as generating complex objects, processing complex data structures, etc.

Python实现生成器模式

以下是Python实现生成器模式的示例代码:

# 定义生成器函数
def simple_generator():
    yield 1
    yield 2
    yield 3

# 使用生成器函数
for i in simple_generator():
    print(i)

输出结果:

1
2
3

在Python中,使用yield关键字定义一个生成器函数,然后在循环中使用该生成器函数。每次调用生成器函数时,它会返回生成器对象,然后迭代器会从上次停止的地方继续执行,直到遇到下一个yield语句。在上面的示例中,我们定义了一个简单的生成器函数simple_generator,它生成了三个整数1、2和3。然后我们使用for循环遍历生成器对象,并打印每个生成的整数。由于生成器是惰性计算的,因此在每次迭代时才会计算下一个值,而不是一次性计算所有值。这使得生成器非常适合处理大量数据或需要节省内存的情况。

在这里插入图片描述

生成器模式在spring中的应用

生成器模式在Spring框架中有多种应用场景,以下是一些常见的应用示例:

  1. 创建复杂的对象:Spring中经常需要创建复杂的对象,这些对象可能包含多个属性,每个属性的值可能需要通过不同的方法获取。使用生成器模式可以将对象的创建过程分解为多个步骤,每个步骤由一个具体的生成器类负责构建,通过控制生成器的组合顺序,可以构建出不同的对象。
  2. 构建流程定义:Spring中可以使用生成器模式定义复杂的流程,将流程的各个步骤抽象为生成器类,通过组合生成器的方式定义整个流程。这样可以使得流程的维护和扩展更加灵活和方便。
  3. 状态改变:在某些情况下,当对象的状态发生改变时,需要调用多个方法才能完成。使用生成器模式可以将状态的改变分解为多个方法,每个方法负责改变对象的一部分状态,从而提高代码的可读性和可维护性。
  4. 实现插件架构:Spring中可以使用生成器模式实现插件架构,通过定义一个接口和多个实现类,将插件的加载和卸载分解为多个步骤,每个步骤由一个具体的生成器类负责实现。这样可以在运行时动态地添加或删除插件,而不需要修改主程序。

生成器模式在Spring中应用广泛,可以提高代码的可读性和可维护性,降低程序的复杂度,使得程序更加灵活和易于扩展。

在这里插入图片描述

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2023-12-25 23:24:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-25 23:24:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-25 23:24:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-25 23:24:03       20 阅读

热门阅读

  1. 爬虫抓取链家二手房数据

    2023-12-25 23:24:03       34 阅读
  2. date工具类

    2023-12-25 23:24:03       31 阅读
  3. C语言中switch语句中的case后()

    2023-12-25 23:24:03       39 阅读
  4. [运维|shell] 编写shell脚本定期清理日志

    2023-12-25 23:24:03       39 阅读
  5. 第6章1-字符串及正则表达式 p63

    2023-12-25 23:24:03       32 阅读
  6. 避免约束系数过大的2种技巧

    2023-12-25 23:24:03       36 阅读
  7. ubuntu22.04上安装charles-proxy

    2023-12-25 23:24:03       34 阅读
  8. GO语言基础笔记(四):并发编程基础

    2023-12-25 23:24:03       33 阅读
  9. 第六章 卷:将磁盘挂载到容器

    2023-12-25 23:24:03       33 阅读
  10. Android 设置系统桌面壁纸

    2023-12-25 23:24:03       35 阅读