设计模式之结构型设计模式(二):工厂模式 抽象工厂模式 建造者模式

工厂模式 Factory

1、什么是工厂模式

工厂模式旨在提供一种统一的接口来创建对象,而将具体的对象实例化的过程延迟到子类或者具体实现中。有助于降低客户端代码与被创建对象之间的耦合度,提高代码的灵活性和可维护性。

定义了一个创建对象的接口,但不负责具体对象的实例化。而是将实例化的责任交给它的子类或者具体实现,这种模式包括抽象工厂、工厂方法和简单工厂等不同形式。

2、为什么使用工厂模式

  1. 降低耦合度:工厂模式将客户端代码与具体的类实现分离,降低它们之间的耦合度,客户端只需要知道工厂接口或者抽象类,而无需关心具体的实现细节。
  2. 可扩展性:当需要添加新的产品类时,只需要创建一个新的具体工厂类和产品类,而不需要修改已有的代码,有助于系统的可扩展性,符合开闭原则。
  3. 隐藏实现细节:工厂模式将对象的创建过程封装在工厂类中,客户端无需知道对象的具体创建细节,有助于隐藏实现细节,提高系统的安全性。

3、如何实现工厂模式

简单工厂模式

简单工厂模式是工厂模式的一种简化形式,包含了一个具体工厂类,负责创建产品的对象。

// 抽象产品类
interface Product {
    void display();
}

// 具体产品类A
class ConcreteProductA implements Product {
    @Override
    public void display() {
        System.out.println("Product A");
    }
}

// 具体产品类B
class ConcreteProductB implements Product {
    @Override
    public void display() {
        System.out.println("Product B");
    }
}

// 简单工厂类
class SimpleFactory {
    public static Product createProduct(String type) {
        switch (type) {
            case "A":
                return new ConcreteProductA();
            case "B":
                return new ConcreteProductB();
            default:
                throw new IllegalArgumentException("Invalid product type");
        }
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Product productA = SimpleFactory.createProduct("A");
        productA.display();  // Output: Product A

        Product productB = SimpleFactory.createProduct("B");
        productB.display();  // Output: Product B
    }
}
工厂方法模式

工厂方法模式定义了一个创建产品的接口,具体的产品创建由其子类负责实现。

// 抽象产品类
interface Product {
    void display();
}

// 具体产品类A
class ConcreteProductA implements Product {
    @Override
    public void display() {
        System.out.println("Product A");
    }
}

// 具体产品类B
class ConcreteProductB implements Product {
    @Override
    public void display() {
        System.out.println("Product B");
    }
}

// 抽象工厂接口
interface Factory {
    Product createProduct();
}

// 具体工厂类A
class ConcreteFactoryA implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

// 具体工厂类B
class ConcreteFactoryB implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Factory factoryA = new ConcreteFactoryA();
        Product productA = factoryA.createProduct();
        productA.display();  // Output: Product A

        Factory factoryB = new ConcreteFactoryB();
        Product productB = factoryB.createProduct();
        productB.display();  // Output: Product B
    }
}

4、是否存在缺陷和不足

  1. 类爆炸:随着产品类的增加,工厂类的数量也会呈现指数级增长,导致类的爆炸,不利于系统的维护。
  2. 违背开闭原则:每次添加新产品都需要修改工厂类,违背了开闭原则,当有新产品加入时,必须修改所有工厂类。

5、如何缓解缺陷与不足

  1. 使用抽象工厂模式:抽象工厂模式将一组相关的产品封装在一起,形成一个产品族,每个具体工厂负责创建一族产品,缓解了类的爆炸问题,
  2. 依赖注入:将工厂的创建过程交给外部来管理,通过依赖注入的方式,避免了工厂类的频繁修改。
  3. 使用反射:可以使用反射机制,动态地创建产品对象,从而减少了工厂类的数量。

通过以上缓解措施,可以在一定程度上提高工厂模式的灵活性和可维护性,使其更好地适应变化。在实际应用中,根据具体场景选择合适的工厂的模式,并结合其他设计模式,以达到代码的清晰和可扩展。

抽象工厂模式 Abstract Factory

1、什么是抽象工厂模式

抽象工厂模式提供了一个接口,用于创建与产品家族相关的对象,无需制定具体类,有助于确保创建的对象能够相互配合使用,而无需指定具体的类。

抽象工厂模式提供了一种将一组相关的产品组合成一个家族的方式,而不必指定具体的类,通过引入抽象工厂接口和一组具体工厂类,为每个产品提供一个独立的工厂,从而使系统更具灵活性。

2、为什么用抽象工厂模式

  1. 产品家族一致性:抽象工厂模式确保创建的对象相互之间是兼容的,属于同一产品家族,有助于保持系统的一致性。
  2. 易于替换:由于客户端只依赖于抽象接口,而不直接依赖具体类,因此可以轻松替换整个产品家族的实现,而无需修改客户端代码。
  3. 隐藏实现细节:客户端无需知道具体产品的实现细节,只需要了解抽象工厂接口,从降低了系统的复杂度。

3、如何实现抽象工厂模式

示例:图形界面库的抽象工厂模式,包含图形界面库中的按钮和文本框。

// 抽象按钮接口
interface Button {
    void display();
}

// 具体按钮A
class ButtonA implements Button {
    @Override
    public void display() {
        System.out.println("Button A");
    }
}

// 具体按钮B
class ButtonB implements Button {
    @Override
    public void display() {
        System.out.println("Button B");
    }
}

// 抽象文本框接口
interface TextBox {
    void display();
}

// 具体文本框A
class TextBoxA implements TextBox {
    @Override
    public void display() {
        System.out.println("TextBox A");
    }
}

// 具体文本框B
class TextBoxB implements TextBox {
    @Override
    public void display() {
        System.out.println("TextBox B");
    }
}

// 抽象工厂接口
interface GUIFactory {
    Button createButton();
    TextBox createTextBox();
}

// 具体工厂A
class GUIFactoryA implements GUIFactory {
    @Override
    public Button createButton() {
        return new ButtonA();
    }

    @Override
    public TextBox createTextBox() {
        return new TextBoxA();
    }
}

// 具体工厂B
class GUIFactoryB implements GUIFactory {
    @Override
    public Button createButton() {
        return new ButtonB();
    }

    @Override
    public TextBox createTextBox() {
        return new TextBoxB();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 使用工厂A创建按钮和文本框
        GUIFactory factoryA = new GUIFactoryA();
        Button buttonA = factoryA.createButton();
        TextBox textBoxA = factoryA.createTextBox();

        buttonA.display();  // Output: Button A
        textBoxA.display(); // Output: TextBox A

        // 使用工厂B创建按钮和文本框
        GUIFactory factoryB = new GUIFactoryB();
        Button buttonB = factoryB.createButton();
        TextBox textBoxB = factoryB.createTextBox();

        buttonB.display();  // Output: Button B
        textBoxB.display(); // Output: TextBox B
    }
}

4、是否存在缺陷和不足

  1. 不易扩展新的产品家族:当需要添加新的产品家族时,需要修改抽象工厂接口及其所有的实现类,违背了开闭原则,使得系统扩展性受限。
  2. 复杂性增加:随着产品家族的增加,抽象工厂模式的类和接口数量可能呈现指数级增长,导致系统复杂性增加。

5、如何缓解缺陷和不足

  1. 使用依赖注入:将工厂的创建过程交给外部来管理,通过依赖注入的方式,避免了工厂类的频繁修改。
  2. 使用反射:可以使用反射机制,动态地创建产品对象,从而减少了工厂类和产品类的数量。
  3. 使用配置文件:将产品家族的配置信息放置在配置文件中,通过读取配置文件的方式动态创建工厂和产品对象,提高了系统的灵活性。

建造者模式 Builder

1、什么是建造者模式

建造者模式旨在通过将复杂对象的构造过程分离成多个简单的步骤,使得同样的创建过程可以创建不同的表示,有助于客户端代码能够根据需求选择构建过程的不同组合,以创建不同属性的对象。

将一个复杂对象的构建与其表示分离,使得同样的创建过程可以创建不同的表示,主要包含以下角色:

  • 产品
  • 抽象建造者
  • 具体建造者
  • 指挥者

2、为什么用建造者模式

  1. 分布创建:建造者模式允许按照步骤构建一个复杂对象,使得客户端代码可以选择性地构建对象的不同部分,灵活性更高。
  2. 隔离复杂性:将构建过程在具体的建造者中,客户端无需关心构建的细节,从而降低了系统的复杂性。
  3. 可扩展性:可以通过增加新的具体的建造者类来扩展系统,而不影响已有的客户端代码。

3、如何实现建造者模式

设计实现一个电脑组装的建造者模式

// 产品类
class Computer {
    private String cpu;
    private String memory;
    private String storage;

    public Computer(String cpu, String memory, String storage) {
        this.cpu = cpu;
        this.memory = memory;
        this.storage = storage;
    }

    // Getters...
    
    public void display() {
        System.out.println("Computer Specs: CPU-" + cpu + ", Memory-" + memory + ", Storage-" + storage);
    }
}

// 抽象建造者
interface ComputerBuilder {
    void buildCPU(String cpu);
    void buildMemory(String memory);
    void buildStorage(String storage);
    Computer getResult();
}

// 具体建造者A
class ConcreteBuilderA implements ComputerBuilder {
    private Computer computer;

    public ConcreteBuilderA() {
        this.computer = new Computer("", "", "");
    }

    @Override
    public void buildCPU(String cpu) {
        computer = new Computer(cpu, computer.getMemory(), computer.getStorage());
    }

    @Override
    public void buildMemory(String memory) {
        computer = new Computer(computer.getCpu(), memory, computer.getStorage());
    }

    @Override
    public void buildStorage(String storage) {
        computer = new Computer(computer.getCpu(), computer.getMemory(), storage);
    }

    @Override
    public Computer getResult() {
        return computer;
    }
}

// 具体建造者B
class ConcreteBuilderB implements ComputerBuilder {
    private Computer computer;

    public ConcreteBuilderB() {
        this.computer = new Computer("", "", "");
    }

    @Override
    public void buildCPU(String cpu) {
        computer = new Computer(cpu, computer.getMemory(), computer.getStorage());
    }

    @Override
    public void buildMemory(String memory) {
        computer = new Computer(computer.getCpu(), memory, computer.getStorage());
    }

    @Override
    public void buildStorage(String storage) {
        computer = new Computer(computer.getCpu(), computer.getMemory(), storage);
    }

    @Override
    public Computer getResult() {
        return computer;
    }
}

// 指挥者
class Director {
    public void construct(ComputerBuilder builder) {
        builder.buildCPU("Intel i5");
        builder.buildMemory("8GB");
        builder.buildStorage("256GB SSD");
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 使用建造者A构建电脑
        ComputerBuilder builderA = new ConcreteBuilderA();
        Director director = new Director();
        director.construct(builderA);
        Computer computerA = builderA.getResult();
        computerA.display();

        // 使用建造者B构建电脑
        ComputerBuilder builderB = new ConcreteBuilderB();
        director.construct(builderB);
        Computer computerB = builderB.getResult();
        computerB.display();
    }
}

4、是否存在缺陷和不足

  1. 指挥者的变动:如果产品的构建步骤发生变化,指挥者类的代码也需要修改,违背了开闭原则。
  2. 不够灵活:当产品的构建步骤很多且相互关联时,建造者模式可能变得复杂且不够灵活。

5、如何缓解缺陷和不足

  1. 使用链式调用:在具体建造者中使用链式调用,使得客户端代码更加简洁,且不容易受到构建步骤变动的影响。
  2. 增加产品的变种:当产品的构建步骤较为复杂时,可以考虑增加产品的变种,以适应不同的构建需求。
  3. 使用反射和配置文件:可以通过反射机制和配置文件来动态配置产品的构建过程,提高系统的灵活性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/251128.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

node.js mongoose简述

目录 官方文档 mongoose Schema Model Query document 关系 官方文档 Mongoose v8.0.3: Getting Started mongoose Mongoose 是一个 Node.js 环境下 MongoDB 的对象建模工具。它提供了一种在应用程序中与 MongoDB 数据库进行交互的方式,使得开发者能够使用…

数据可视化?这些平台能处

图表在各行各业都起到举重若轻的作用,无论是项目汇报、业绩分析,亦或是数据挖掘、统计分析,良好的可视化可以为我们的阐述起到画龙点睛的效果。在一篇文章中,如果只有密密麻麻的文字堆积,无论是谁恐怕都无法长期保持注…

mysql !=索引为什么失效

可以先看这个:Mysql查询条件为大于时,不走索引失效场景-CSDN博客 如下建立了联合索引, 注意查询phone是用不对劲了索引,key_len82 改为 !时, key key_len没内容,说明没有走索引,为什么没有走&…

DIY电脑装机机箱风扇安装方法

作为第一次自己diy一台电脑主机的我,在经历了众多的坑中今天来说一下如何安装机箱风扇的问题 一、风扇的数量 1、i3 xx50显卡 就用一个cpu散热风扇即可 2、i5 xx60 一个cpu散热风扇 一个风扇即可 3、i7 xx70 一个cpu散热 4个风扇即可 4、i9 xx80 就需要7个以…

Ubuntu安装蓝牙模块pybluez以及问题解决方案【完美解决】

文章目录 简介问题及解决办法总结 简介 近期因工程需要在Ubuntu中使用蓝牙远程一些设备。安装Bluetooth的Python第三方软件包pybluez时遇到很多问题,一番折腾后完美解决。此篇博客进行了梳理和总结,供大家参考。 问题及解决办法 pip install pybluez安…

数据迁移测试经验分享

以下为作者观点: 数据迁移,是在保证新旧系统业务连续性的前提下,将数据从旧数据库迁移到新数据库的过程,测试前通过迁移策略和方案了解新旧系统数据如何重构与关联,测试过程需确保数据迁移的正确性,主要体…

Lambda 表达式与C++并发编程

Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。 // …

Easy Excel生成复杂下Excel模板(下拉框)给用户下载

引言 文件的下载是一个非常常见的功能,也有一些非常好的框架可以使用,这里我们就介绍一种比较常见的场景,下载Excel模版,导入功能通常会配有一个模版下载的功能,根据下载的模版,填充数据然后再上传。 需求…

CAN 五: CAN编程实践

1、CAN基本驱动步骤 (1)CAN参数初始化 工作模式、波特率等函数:HAL_CAN_Init (2)使能CAN时钟和初始化相关引脚 GPIO模式设为复用功能模式函数:HAL_CAN_MspInit(CAN的初始化回调函数) (3)设置过滤器 过滤器的配置函数:HAL_CAN_ConfigFil…

客户端SDK测试是什么?如何测?

01、是什么 客户端SDK是为第三方开发者提供的软件开发工具包,包括SDK接口、开发文档和Demo示例等。SDK和应用之间是什么关系呢?以云信即时消息服务为例,如下图所示,应用客户端通过调用云信SDK接口,进行消息等数据查询…

用EnumSet代替位域

在Java中,可以使用EnumSet来代替位域,以提高代码的可读性和类型安全性。下面是一个简单的例子,演示如何使用EnumSet来管理一组枚举值: import java.util.EnumSet;// 定义一个枚举类型表示权限 enum Permission {READ, WRITE, EXE…

【Java】使用递归的方法获取层级关系数据demo

使用递归来完善各种业务数据的层级关系的获取 引言:在Java开发中,我们通常会遇到层层递进的关系型数据的获取问题,有时是树状解构,或金字塔结构,怎么描述都行,错综复杂的关系在程序中还是可以理清的。 这…

【MySQL】SQL通用语法 、介绍SQL分类

SQL通用语法 1.SQL语句可以单行或多行书写,以分号结尾 2.MySQL数据库的SQL语句不区分大小写,关键字建议使用大写。 3.注释: 单行注释: -- 或 # 多行注释: /* */ SQL分类 SQL分类主要分为4类 分别是 DDL DML DQL DCL

向华为学习:基于BLM模型的战略规划研讨会实操的详细说明,含研讨表单(一)

前面,华研荟用了三篇文章介绍华为战略规划的时候使用的其中一个工具:五看三定。一句话来说,五看三定是通过“五看”来知己知彼,然后设计业务,在选定的业务领域(方向)确定战略控制点,…

libp2p 快速开始

文章目录 第一部分:libp2p 快速入门一、什么是libp2plibp2p 发展历程libp2p的特性p2p 网络和我们熟悉的 client/server 网络的区别: 二、Libp2p的实现目标三、Libp2p的用途四、运行 Libp2p 协议流程libp2p 分为三层libp2p 还有一个局域网节点发现协议 mD…

新能源汽车的“一池春水”,或许不再由价格战掀起波澜?

2005年12月15日,丰田普锐斯混合动力车进入中国,拉开了国内新能源汽车发展的序幕。18年后的今天,国产及进口的新能源汽车已经渗透我国超三分之一的乘用车市场,与油车二分天下的愿景渐趋实现。 今年11月,随着购车需求进…

Mac专用投屏工具AirServer 7 .27 for Mac破解版2024最新免费下载及 2024激活码进行详细解析

AirServer是一款多平台无线屏幕镜像推送软件,能够将iPhone、iPad等移动设备的画面投射到电视、投影仪等大屏幕设备上。而对于尝试使用AirServer的用户来说,激活码是不可或缺的一部分,本文将从多个方面对AirServer 2024激活码进行详细解析。 一…

管理类联考——数学——真题篇——按知识分类——几何——解析几何

文章目录 解析几何2023真题(2023-07)-几何-解析几何-最值-画图求最值-两线相减求最大-联想三角形的“两边差小于第三边”,当为第三边为最大真题(2023-19)-几何-解析几何-最值-画图求最值-圆方程画出圆的形状-两点间距离…

TranslatePress Pro 2.6.8 + Addons – WordPress 多语言插件说明介绍

关于TranslatePress Pro 2.6.8 Addons – WordPress多语言插件 TranslatePress Pro Nulled 直接从前端翻译您的 WordPress 网站的更好方式,完全支持 WooCommerce、复杂主题和网站构建器。TranslatePress Pro WordPress 翻译插件,易于使用进行更改。 T…

智能优化算法应用:基于海洋捕食者算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于海洋捕食者算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于海洋捕食者算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.海洋捕食者算法4.实验参数设定5.算法…