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

news2024/11/24 16:06:44

工厂模式 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. 使用反射和配置文件:可以通过反射机制和配置文件来动态配置产品的构建过程,提高系统的灵活性。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

spring 笔记九 Spring AOP

Spring 的 AOP 简介 什么是AOP AOP 为Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 AOP 是OOP 的延续,是软件开发中的一个热点,也是Spring框架…

【Spark精讲】Spark存储原理

目录 类比HDFS的存储架构 Spark的存储架构 存储级别 RDD的持久化机制 RDD缓存的过程 Block淘汰和落盘 类比HDFS的存储架构 HDFS集群有两类节点以管理节点-工作节点模式运行,即一个NameNode(管理节点)和多个DataNode(工作节点)。 Namenode管理文件系统的命名空…

BKP 备份寄存器 RTC 实时时钟-stm32入门

这一章节我们要讲的主要内容是 RTC 实时时钟,对应手册,是第 16 章的位置。 实时时钟这个东西,本质上是一个定时器,但是这个定时器,是专门用来产生年月日时分秒,这种日期和时间信息的。所以学会了 STM32 的…

Java系列-ConcurrentHashMap-addCount

1.addCount public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>implements ConcurrentMap<K,V>, Serializable {private final void addCount(long x, int check) {CounterCell[] as; long b, s;//1.counterCells不为null//2.或者 x加到baseCou…

挑战52天学小猪佩奇笔记--day24

52天学完小猪佩奇--day24 ​【本文说明】 本文内容来源于对B站UP 脑洞部长 的系列视频 挑战52天背完小猪佩奇----day24 的视频内容总结&#xff0c;方便复习。强烈建议大家去关注一波UP&#xff0c;配合UP视频学习。 注&#xff1a;这集开始变成一段一段的猜台词&#xff0c;加…

网站提示“不安全”

当你在浏览网站时&#xff0c;有时可能会遇到浏览器提示网站不安全的情况。这通常是由于网站缺乏SSL证书所致。那么&#xff0c;从SSL证书的角度出发&#xff0c;我们应该如何解决这个问题呢&#xff1f; 首先&#xff0c;让我们简单了解一下SSL证书。SSL证书是一种用于保护网站…

pybind11:对比C++和Python解线性方程组的速度

前言 上篇博客介绍了如何在用pybind11实现ndarray和C数组的转换自由&#xff0c;pybind11&#xff1a;实现ndarray转C原生数组&#xff08;没看过的朋友可以去看一看&#xff09;下面我们以一个实际的算法例子演示一下如何使用这个技术&#xff0c;方便的实现 Python 调用 C 写…

Java架构师系统架构高可用维度分析

目录 1 导语2 可用性介绍3 本地高可用-集群、分布式4 本地高可用-数据逻辑保护5 异地容灾-双活、两地三中心6 异地容灾-DRP规划&BCP业务连续性7 多活和妥协方案8 高可用流程9 总结想学习架构师构建流程请跳转:Java架构师系统架构设计 1 导语 Java架构师在进行系统架构设…

蓝桥杯专题-真题版含答案-【排序法 - 改良的选择排序】【插补搜寻法】【稀疏矩阵】【欧拉与鸡蛋】

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

【golang/g3n】3D游戏引擎G3N的windows安装与测试

目录 说在前面安装测试 说在前面 操作系统&#xff1a;win 11go version&#xff1a;go1.21.5 windows/amd64g3n版本&#xff1a;github.com/g3n/engine v0.2.0其他&#xff1a;找了下golang 3d相关的库&#xff0c;目前好像就这个比较活跃 安装 按照官方教程所说&#xff0c;…

ES6 面试题 | 13.精选 ES6 面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

IDEA中alt enter不显示创建实现类快捷键

alt enter不显示创建实现类快捷键是因为idea中的设置没打开&#xff0c;按照一下设置打开就可以了。 点击setting-->>editor-->>intentions-->>java下的declaration 如下图所示&#xff1a;

PXI/PCIe/VPX机箱 ARM|x86 + FPGA测试测量板卡解决方案

PXI便携式测控系统是一种基于PXI总线的便携式测试测控系统&#xff0c;它填补了现有台式及机架式仪器在外场测控和便携测控应用上的空白&#xff0c;在军工国防、航空航天、兵器电子、船舶舰载等各个领域的外场测控场合和科学试验研究场合都有广泛的应用。由于PXI便携式测控系统…

HiveSql语法优化一 :分组聚合优化

Hive中未经优化的分组聚合&#xff0c;是通过一个MapReduce Job实现的。Map端负责读取数据&#xff0c;并按照分组字段分区&#xff0c;通过Shuffle&#xff0c;将数据发往Reduce端&#xff0c;各组数据在Reduce端完成最终的聚合运算。 Hive对分组聚合的优化主要围绕着减少Shuf…

Linux 基本语句_15_Tcp并发服务器

原理&#xff1a; 利用父子进程。父进程接收客户端的连接请求&#xff0c;子进程处理客户端的数据处理操作&#xff0c;两者各施其职。最终实现能够多个客户端连接一个服务端的操作。 代码&#xff1a; 服务端代码&#xff1a; #include <stdio.h> #include <sys/…

时序预测 | Python实现LSTM-Attention-XGBoost组合模型电力需求预测

时序预测 | Python实现LSTM-Attention-XGBoost组合模型电力需求预测 目录 时序预测 | Python实现LSTM-Attention-XGBoost组合模型电力需求预测预测效果基本描述程序设计参考资料预测效果 基本描述 该数据集因其每小时的用电量数据以及 TSO 对消耗和定价的相应预测而值得注意,从…

Eslint 要被 Oxlint替换了吗

什么是 Oxlint 由于最近的rust在前端领域的崛起,基于rust的前端生态链遭到rust底层重构,最近又爆出OxLint,是一款基于Rust的linter工具。Oxlint在国外前端圈引起热烈讨论,很多大佬给出了高度评价。 事实上,Oxlint 是 Oxc 项目旗下的一款产品,专为 JavaScript 和 TypeSc…

SLAM算法与工程实践——SLAM基本库的安装与使用(5):Ceres优化库

SLAM算法与工程实践系列文章 下面是SLAM算法与工程实践系列文章的总链接&#xff0c;本人发表这个系列的文章链接均收录于此 SLAM算法与工程实践系列文章链接 下面是专栏地址&#xff1a; SLAM算法与工程实践系列专栏 文章目录 SLAM算法与工程实践系列文章SLAM算法与工程实践…

【️接口和抽象类的区别,如何选择?】

✅接口和抽象类的区别&#xff0c;如何选择&#xff1f; ✅ 接口和抽象类的区别✅方法定义✅修饰符✅构造器✅继承和实现✅单继承 、 多实现✅职责不同 ✅什么是模板方法模式&#xff0c;有哪些应用呢&#xff1f;✅典型理解✅示例&#x1f4a1;思考 ✅你在工作中是如何使用设计…

Swin-Transformer 在图像识别中的应用

1. 卷积神经网络简单介绍 图像识别任务主要利用神经网络对图像进行特征提取&#xff0c;最后通过全连接层将特征和分类个数进行映射。传统的网络是利用线性网络对图像进行分类&#xff0c;然而图像信息是二维的&#xff0c;一般来说&#xff0c;图像像素点和周围邻域像素点相关…