【设计模式 03】抽象工厂模式

一个具体的工厂,可以专门生产单一某一种东西,比如说只生产手机。但是一个品牌的手机有高端机、中端机之分,这些具体的属于某一档次的产品都需要单独建立一个工厂类,但是它们之间又彼此关联,因为都共同属于一个品牌。我们说这种叫做“多类”对象

除了手机之外,还有比如沙发、茶几、椅子,不同于手机的高端型号和低端型号,取而代之的可以是不同的样式风格,比如古典风格的和现代风格的。每一种风格的产品都需要单独建立一个工厂类,但是他们本质上都属于同一样东西。我们可以从这个角度理解“多类对象”,即,就是同一对象的多种类别。

图中包含以下元素:

  • 抽象产品接口:AbstractProduct
  • 具体产品类:ConcreteProduct
  • 抽象工厂接口:AbstractFactory
  • 具体工厂类:ConcreateFactory

 Java代码:

// 1. 定义抽象产品
// 抽象产品A
interface ProductA {
    void display();
}

// 抽象产品B
interface ProductB {
    void show();
}

// 2. 实现具体产品类
// 具体产品A1
class ConcreteProductA1 implements ProductA {
    @Override
    public void display() {
        System.out.println("Concrete Product A1");
    }
}

// 具体产品A2
class ConcreteProductA2 implements ProductA {
    @Override
    public void display() {
        System.out.println("Concrete Product A2");
    }
}

// 具体产品B1
class ConcreteProductB1 implements ProductB {
    @Override
    public void show() {
        System.out.println("Concrete Product B1");
    }
}

// 具体产品B2
class ConcreteProductB2 implements ProductB {
    @Override
    public void show() {
        System.out.println("Concrete Product B2");
    }
}

// 3. 定义抽象工厂接口
interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// 4. 实现具体工厂类
// 具体工厂1,生产产品A1和B1
class ConcreteFactory1 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB1();
    }
}

// 具体工厂2,生产产品A2和B2
class ConcreteFactory2 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB2();
    }
}

// 客户端代码
public class AbstractFactoryExample {
    public static void main(String[] args) {
        // 使用工厂1创建产品A1和产品B1
        AbstractFactory factory1 = new ConcreteFactory1();
        ProductA productA1 = factory1.createProductA();
        ProductB productB1 = factory1.createProductB();
        productA1.display();
        productB1.show();

        // 使用工厂2创建产品A2和产品B2
        AbstractFactory factory2 = new ConcreteFactory2();
        ProductA productA2 = factory2.createProductA();
        ProductB productB2 = factory2.createProductB();
        productA2.display();
        productB2.show();
    }
}

为了避免跟之前的工厂方法模式混淆,这里做一个区别:

  • 简单工厂模式:一个工厂方法创建所有具体产品
  • 工厂方法模式:一个工厂方法创建一个具体产品
  • 抽象工厂模式:一个工厂方法创建一个具体产品的某一类

典型的应用场景是,使用抽象工厂模式来创建与不同数据库的连接对象。

总结一下就是抽象工厂模式特别适用于一系列相关或相互依赖的产品被一起创建的情况。

当需要增加新产品时(是新产品而不是某一产品的新型号),则需要增加新的具体产品类,然后修改抽象工厂接口以及所有的具体工厂类,扩展性相对较差。

【设计模式专题之抽象工厂模式】3. 家具工厂

CPP版代码:

#include <iostream>
#include <string>
 
// 抽象椅子接口
class Chair {
public:
    virtual void showInfo() = 0;
};
 
// 具体现代风格椅子
class ModernChair : public Chair {
public:
    void showInfo() override {
        std::cout << "modern chair" << std::endl;
    }
};
 
// 具体古典风格椅子
class ClassicalChair : public Chair {
public:
    void showInfo() override {
        std::cout << "classical chair" << std::endl;
    }
};
 
// 抽象沙发接口
class Sofa {
public:
    virtual void displayInfo() = 0;
};
 
// 具体现代风格沙发
class ModernSofa : public Sofa {
public:
    void displayInfo() override {
        std::cout << "modern sofa" << std::endl;
    }
};
 
// 具体古典风格沙发
class ClassicalSofa : public Sofa {
public:
    void displayInfo() override {
        std::cout << "classical sofa" << std::endl;
    }
};
 
// 抽象家居工厂接口
class FurnitureFactory {
public:
    virtual Chair* createChair() = 0;
    virtual Sofa* createSofa() = 0;
};
 
// 具体现代风格家居工厂
class ModernFurnitureFactory : public FurnitureFactory {
public:
    Chair* createChair() override {
        return new ModernChair();
    }
 
    Sofa* createSofa() override {
        return new ModernSofa();
    }
};
 
// 具体古典风格家居工厂
class ClassicalFurnitureFactory : public FurnitureFactory {
public:
    Chair* createChair() override {
        return new ClassicalChair();
    }
 
    Sofa* createSofa() override {
        return new ClassicalSofa();
    }
};
 
int main() {
    // 读取订单数量
    int N;
    std::cin >> N;
 
    // 处理每个订单
    for (int i = 0; i < N; i++) {
        // 读取家具类型
        std::string furnitureType;
        std::cin >> furnitureType;
 
        // 创建相应风格的家居装饰品工厂
        FurnitureFactory* factory = nullptr;
        if (furnitureType == "modern") {
            factory = new ModernFurnitureFactory();
        } else if (furnitureType == "classical") {
            factory = new ClassicalFurnitureFactory();
        }
 
        // 根据工厂生产椅子和沙发
        Chair* chair = factory->createChair();
        Sofa* sofa = factory->createSofa();
 
        // 输出家具信息
        chair->showInfo();
        sofa->displayInfo();
 
        // 释放动态分配的对象
        delete chair;
        delete sofa;
        delete factory;
    }
 
    return 0;
}

 

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

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

相关文章

视觉Transformers中的位置嵌入 - 研究与应用指南

视觉 Transformer 中位置嵌入背后的数学和代码简介。 自从 2017 年推出《Attention is All You Need》以来&#xff0c;Transformer 已成为自然语言处理 (NLP) 领域最先进的技术。 2021 年&#xff0c;An Image is Worth 16x16 Words 成功地将 Transformer 应用于计算机视觉任务…

【go语言开发】yaml文件配置和解析

本文主要介绍使用第三方库来对yaml文件配置和解析。首先安装yaml依赖库&#xff1b;然后yaml文件中配置各项值&#xff0c;并给出demo参考&#xff1b;最后解析yaml文件&#xff0c;由于yaml文件的配置在全局中可能需要&#xff0c;可定义全局变量Config&#xff0c;便于调用 文…

面试题HTML+CSS+网络+浏览器篇

文章目录 Css预处理sass less是什么&#xff1f;为什么使用他们怎么转换 less 为 css&#xff1f;重绘和回流是什么http 是什么&#xff1f;有什么特点HTTP 协议和 HTTPS 区别什么是 CSRF 攻击HTML5 新增的内容有哪些Css3 新增的特性flex VS grid清除浮动的方式有哪些&#xff…

SAR ADC学习笔记(3)

一、SAR ADC采样电路 1.采样网络的时域响应&#xff1a;采保信号 2.采样网络的KT/C噪声 3.采样抖动 采样开关的种类 1.单MOS管开关 2.传输门开关 3.栅极自举&#xff08;Bootstrap&#xff09;开关 结论&#xff1a;M4的衬底需要和B点短接&#xff0c;保证B点能够到达高压&…

完美解决Iframe嵌入帆软报表出现跨域cookie写不进去的问题

随着google chrome对第三方cookie的限制越来越狠,现在发现之前使用iframe嵌入的帆软报表已经不好使了。官方现在解决iframe嵌入帆软报表出现跨域导致cookie写不进去的方案是主推 统一主域名的方案(谷歌浏览器单点登录失败- FineReport帮助文档 - 全面的报表使用教程和学习资料…

大唐杯学习笔记:Day5

1.1 小区搜索 搜索流程 PLMN选择 自动模式&#xff1a;UE根据NAS的请求或自主地向NAS报告可用的PLMN 手动模式&#xff1a;通过手动选择一个可用的VPLMN获取正常服务 频点选择 5G NR中,3GPP主要指定了两个频率范围,一个是6GHZ以下,另一个是毫米波,分别称之为FR1和FR2。 N…

稀碎从零算法笔记Day5-LeetCode:轮转数组

题型&#xff1a;数组、数学、双指针 前言&#xff1a;LC说你得用三种方法做出来(悲) 链接&#xff1a;189. 轮转数组 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 …

专业145+总分410+西工大西北工业大学827信号与系统考研经验电子信息与通信工程,海航,真题,大纲,参考书。

经过一年的努力&#xff0c;分数终于出来。今年专业课827信号与系统145&#xff08;很遗憾差了一点点满分&#xff0c;没有达到Jenny老师的最高要求&#xff09;&#xff0c;数一130&#xff0c;英语和政治也都比较平衡&#xff0c;总分410分&#xff0c;当然和信息通信考研Jen…

学习java第一天(下载并配置环境+写第一个java程序)

一.安装 1.下载 直接去官网上选择与你电脑符合的版本下载 官网链接Java Archive Downloads - Java SE 8u211 and later &#xff08;拿我的为例 Windows x64版本&#xff09; ​ 2.然后安装好exe&#xff08;要让自己知道在哪&#xff09; 3.配置环境 大佬链接&#xff1…

蓝桥杯前端Web赛道-新鲜的蔬菜

蓝桥杯前端Web赛道-新鲜的蔬菜 题目链接&#xff1a;1.新鲜的蔬菜 - 蓝桥云课 (lanqiao.cn) 题目要求如下&#xff1a; 其实很容易联想到使用flex布局&#xff0c;这是flex布局一种非常经典的骰子布局&#xff0c;推荐Flex 布局教程&#xff1a;实例篇 - 阮一峰的网络日志 (r…

Java基于SpringBoot网上超市的设计与实现论文

摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0c;所以对于信息的宣传和管理就很关键。因此超市商品销售信…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:点击回弹效果)

设置组件点击时回弹效果。 说明&#xff1a; 从API Version 10开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 clickEffect clickEffect(value: ClickEffect | null) 设置当前组件点击回弹效果。 系统能力&#xff1a; SystemCapabilit…

SQL技巧笔记(一):连续3人的连号问题—— LeetCode601.体育馆的人流量

SQL 技巧笔记 前言&#xff1a;我发现大数据招聘岗位上的应聘流程都是需要先进行笔试&#xff0c;其中占比很大的部分是SQL题目&#xff0c;经过一段时间的学习之后&#xff0c;今天开了一个力扣年会员&#xff0c;我觉得我很有必要去多练习笔试题目&#xff0c;这些题目是有技…

Linux - 进程概念

1、冯诺依曼体系结构 我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体系&#xff1b; 截至目前&#xff0c;我们所认识的计算机&#xff0c;都是有一个个的硬件组件组成&#xff1a; 输入单元&#xff1a;…

浏览器发出一个请求到收到响应步骤详解

前言 在网络通信中&#xff0c;浏览器向Web服务器发送HTTP请求消息的过程是一个复杂而精密的环节&#xff0c;涉及到URL解析、DNS解析、数据拆分、路由表规则和MAC头部添加等一系列步骤。本文将深入探讨这一过程的每个环节&#xff0c;帮助读者更全面地了解浏览器与Web服务器之…

肠道菌群参与利那洛肽对便秘型肠易激综合征 (IBS-C) 患者的影响:一项多中心、前瞻性、前后对照研究

谷禾健康 肠易激综合征 (IBS) 是一种普遍存在的、症状驱动的慢性疾病&#xff0c;其特征是腹部不适和排便不规律&#xff0c;估计影响全球 11.2% 的人口。这些患者中大约三分之一被诊断患有便秘型肠易激综合征&#xff08;IBS-C&#xff09;&#xff0c;这是IBS 的一种亚型。 鉴…

JVM 第二部分-1(程序计数器,虚拟机栈,本地方法栈)

第二部分&#xff1a;运行时数据区 1.程序计数器&#xff1a; 全称是程序计数寄存器&#xff0c;像CPU的寄存器一样&#xff0c;存放线程的下一条指令的地址。每个线程都有一个 &#xff08;区域小&#xff0c;执行速度快&#xff0c;不会有垃圾回收&#xff0c;也不会报oom错…

【外汇天眼】外汇投资策略:区间突破交易系统

RangeBreak系统介绍 RangeBreak区间突破交易系统被市场广泛用于日内交易&#xff0c;曾经连续多年在《美国期货杂志》盈利交易系统排行榜中位居前十。 目前该交易系统也仍旧被很多专业机构和个人投资者所推崇。 交易者可根据自己的交易习惯和性格特点进行改进&#xff0c;并不…

网络编程 24/3/4 作业

1、广播 发送端 #include <myhead.h> int main(int argc, const char *argv[]) {//创建套接字int sfdsocket(AF_INET,SOCK_DGRAM,0);if(sfd-1){perror("socket error");return -1;}//设置当前套接字允许广播属性int broadcast1;if(setsockopt(sfd,SOL_SOCKET…

numpy数据操作

numpy数据操作 读取数据 # numpy读取数据np.loadtxt(fname, 文件、字符串或产生器, 也可以是压缩文件dtypenp.float, 数据类型, 可选, 即确认csv的字符串以什么数据类型读入数组中, 默认为np.floatdelimiterNone, 分割读取的字符串, 默认是…
最新文章