设计模式(1) 创建型模式和抽象工厂(Abstract Factory)

2023-11-12

问题聚焦:分别用一句话概括这节的几个知识点
什么是创建型模式:抽象了实例化过程
创建型模式有哪些:抽象工厂,工厂方法,原型模式,生成器模式
什么是抽象工厂(AbstractFactory)模式:与接口交互,获得一系列相关或互相依赖的对象实例。


创建型模式
两个主旋律:
它们都将关于该系统使用哪些具体的类的信息封装起来
它们隐藏了这些类的实例是如何被创建和放在一起的
Demo: 迷宫的创建
关注的问题:
  • 迷宫的构件:Room,Wall,Door
  • 创建迷宫:使用一系列操作将构件增加到迷宫中,然后连接它们,切忌不可以通过硬编码的方式增加构件
  • 增加新的构件:如只有咒语才能打开的Door, 以及如何比较容易的将这些新构件添加到迷宫中
要想很好的实现上面的要求,硬编码是绝对不可以的。
在使用创建型模式解决这些问题之前,先说明一下这个迷宫游戏的一些类和接口的设定
1 构件的类图
Enter()方法决定你下一个转向将要进入什么,是一个新的房间,或是一个墙壁(就是无法通过)。
2 MazeGame:创建迷宫类
MazeGame::Createmaze方法:创建迷宫方法,这是下面所介绍的模式的最重要的接口处
简述:几种创建型模式如何解决这个问题:
1 工厂方法模式(Factory Method)
如果CreateMaze调用虚函数而不是构造器来创建它所需要的房间,墙壁和门,那么你可以创建一个MazeGame的子类并重定义这些虚函数,从而改变被实例化的类。
2 抽象工厂模式(Abstract Factory)
如果传递一个对象给CreateMaze作参数来创建房间,墙壁和门,那么你可以传递不同的参数来改变房间、墙壁和门的类。
3 建造者模式(Builder)
如果传递一个对象给CreateMaze, 这个对象可以在它所在的迷宫中使用增加房间、墙壁和门的操作,来全面创建一个新的迷宫,那么你可以使用继承来改变迷宫的一些部分或该迷宫被创造的方式。
4 原型模式(Prototype)
如果CreateMaze由多种原型的房间,墙壁和门对象参数化,它拷贝并将这些对象增加到迷宫中,那么你可以用不同的对象替换这些原型对象以改变迷宫的构成。
抽象工厂 (Abstract Factory)
意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
Demo:
考虑一个支持多种界面风格的用户界面工具包。
界面风格包括滚动条、窗口和按钮等窗口组件的外观和行为。
要求:保证界面风格的可移植性和灵活性。
设计:
抽象类WidgetFactory类,这个类声明了一个用来创建每一类基本窗口组件的接口
每一类窗口组件都有一个抽象类,而具体子类则实现了抽口组件的特定的风格

使用:
每一种风格标准都对应于一个具体的WidgetFactory子类.
每一子类实现那些用于创建合适风格标准的创口组件的操作.
客户仅与抽象类定义的接口交互,而不使用特定的具体类的接口.
场景:
  • 一个系统要独立于它的产品的创建、组合和表示时
  • 一个系统要由多个产品系列中的一个来配置时
  • 当要强调一系列相关的产品对象的设计以便进行联合使用时
  • 当提供一个产品类库,而只想显示它们的接口而不是实现时
结构:
和上面的窗口组件的创建的设计很相似
参与者
  • AbstractFactory:声明一个创建抽象产品对象的操作接口
  • ConcreteFactory:实现创建具体产品对象的操作
  • AbstractProduct:为一类产品对象声明一个接口
  • ConcreteProduct:定义一个将被相应的具体工厂创建的产品对象,实现AbstractProduct接口
  • Client:仅使用由AbstractFactory和AbstractProduct类声明的接口
协作
通常在运行时刻创建一个ConcreteFactory类的实例,这一具体的工厂创建具有特定实现的产品对象。为创建不同的产品对象,客户应使用不同的具体工厂
AbstractFactory将产品对象的创建延迟到它的ConcreteFactory子类
优点
  • 分离了具体的类:用户只通过抽象接口获得实例,被隔离的信息有:创建产品对象的责任和过程,类的实现,类名
  • 易于交换产品的系列:一个具体工厂类在一个应用中只出现一次,即是一个单例,所以如果想更换产品系列,只需要使用不同的具体工厂即可,所有生产的接口都是一样的。
  • 有利于产品的一致性:当产品对象被设计在一起工作时,一个应用一次只能使用同一个系列中的对象。
缺点
  • 难以支持新种类的产品:抽象工厂接口确定了可以被创建的产品集合,如果要支持新种类的产品,就需要扩展该工厂类和其所有子类的相关接口。
实现
将工厂作为单件:一个应用中一般每个产品系列只需要一个具体工厂实例
创建产品:
通常为每一个产品定义一个工厂方法,一个具体的工厂将为每个产品重定义该工厂方法(Factory Method)以指定产品
如果有多个可能的产品系列,具体工厂也可以使用原型(Prototype)模式来实现。具体工厂使用产品系列中每个产品的原型实例来初始化,且它通过复制它的原型来创建新的产品。
定义可扩展的工厂
增加一种新的产品要求改变AbstractFactory的接口以及所有与它相关的类。
一个更灵活但不太安全的设计是给创建对象的操作增加一个参数,该参数指定了将被创建的对象的种类。使用这种方法,AbstractFactrory只需要一个Make操作和一个指示要创建对象的种类的参数。

代码示例  
使用抽象工厂模式创建之前我们所讨论的迷宫
类MazeFactory可以创建迷宫的组件。
class MazeFactory {
public:
    MazeFactory();

    virtual Maze* MakeMaze() const
        { return new Maze; }
    virtual Wall* MakeWall() const
        { return new Wall; }
    virtual Room* MakeRoom(int n) const
        { reutrn new Room(n); }
    virtual Door* MakeDoor(Room* r1, Room* r2) const
        { return new Door(r1, r2); }
};
以MazeFactory为参数的新版本的CreateMaze成员函数
Maze* MazeGame::CreateMaze (MazeFactory& factory) {
    Maze* aMaze = factory.MakeMaze();
    Room* r1 = factory.MakeRoom(1);
    Room* r2 = factory.MakeRoom(2);
    Door* aDoor = factory.MakeDoor(r1, r2);

    aMaze->AddRoom(r1);
    aMaze->AddRoom(r2);
    
    r1->SetSide(North, factory.MakeWall());
    r1->SetSide(East, aDoor);
    ......      // 初始化room1, 和room2的四周
    
    return aMaze;
}
创建MazeFactory的子类EnchantedMazeFactory,这是一个创建施了魔法的迷宫的工厂
class EnchantedMazeFactory : public MazeFactory {
public:
    EnchantedMazeFactory();
    
    virtual Room* MakeRoom(int n) const
        { return new EnchantedRoom(n , CastSpell()); }

    virtual Door* MakeDoor(Room* r1, Room* r2) const
        { return new DoorNeedingSpell(r1, r2); }

protected:
    spell* CastSpell() const;
};

CreateMaze方法接收一个EnchantedMazeFactory实例来建造施了魔法的迷宫
MazeGame game;
EnchantedMazeFactory factory;
game.CreateMaze(factory);

相关模式:
AbstractFactory类通常用工厂方法实现,但它们也可以用原型(Prototype)实现。
一个具体的工厂通常是一个单件(Singleton)。
参考资料:
《设计模式》
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

设计模式(1) 创建型模式和抽象工厂(Abstract Factory) 的相关文章

  • 单例模板作为 C++ 中的基类[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 根据C 单例设计模式 https stackoverflow com questions 1008019 c singleton design
  • 线程安全枚举单例

    枚举非常适合创建单例 我知道枚举方法不是线程安全的 所以我尝试使其成为线程安全的 任何人都可以确认此实施是否正确 这么多地方用static和volatile好不好 可以优化吗 由于内部类是私有的 所以我必须在枚举中创建函数来访问内部类功能
  • 如何在单例类中使用DbContext?

    我实现了一个类EUMemberChecker它负责检查一个国家是否是欧盟成员国 为了完成其工作 该类包含一个方法public bool IsEUMember string country 用于检查一个国家是否是欧盟成员的数据存储在 Post
  • 如果父对象不是单例,那么子对象也是单例吗?

    我有一个不是单例的 Dao 从他扩展的其他对象 是否是单例 代码示例
  • 我的 Objective-C 单例应该是什么样子? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • PHP5中单例与工厂模式结合

    在 PHP5 中将单例设计模式与工厂方法模式结合使用的最佳方法是什么 我最简单的使用场景是对每种数据库类型仅实例化选择性数据库连接一次 用于数据库连接的单例工厂 class Registry private static objects p
  • 从其他进程向 WPF 单例应用程序发送数据

    我有一个 WPF 单例应用程序 其中任何时候只有一个实例在运行 如果用户尝试启动另一个实例 我们检查它是否已经在运行 然后我们终止这个新进程并将现有进程置于前面 现在 我们需要从另一个进程 可以是 xls word 或另一个独立应用程序 打
  • 在 Android 中使用 Service 作为单例

    创建一个不好的做法吗 Service作为单身人士工作 我的意思是一个Service它永远不会停止 并且包含一些其他引擎和Activities会使用 所以Service可能有类似的东西 public class CustomService e
  • 为什么这种双重检查锁定是正确的? (。网)

    我读过很多关于双重检查锁定的危险的文章 我会尽力避免它 但话虽如此 我认为他们读起来非常有趣 我正在阅读 Joe Duffy 的这篇关于使用双重检查锁定实现单例的文章 http www bluebytesoftware com blog P
  • 仅当重新初始化继承类中的实例变量时,PHP 中使用单例模式的类继承才有效。但为什么?

    我有一个带有单例函数的主类实例 和相关变量 实例 现在我创建几个子类并让主类继承 我没有重新定义单例函数和变量 因为继承很有用 不幸的是 每个实例都指向第一个子类 仅当在子类中 实例变量被初始化为null它有效 但为什么呢 有了关键词sta
  • 集群环境下的Spring Singleton

    正如中所讨论的this https stackoverflow com questions 1194129 singleton in cluster environmentpost 不适合使用单例聚集的环境 因为不同 JVM 中有多个单例对
  • Android 中 Activity 之间的对象共享

    您好 我有一个关于在整个应用程序中传递对象的问题 假设我想在整个应用程序中拥有一个大的自定义对象 该对象将被多个活动和服务使用 我一开始做的就是这样的 首先 我创建了一个 Application 类并定义了一个单例对象 public cla
  • Java:基于 Web 的应用程序中的单例类实例

    我在 Web Application 中有这个 Singleton 类 public class MyDAO private static MyDAO instance private MyDAO public static MyDAO g
  • MVC和依赖注入,被迫使用单例Controller?

    我正在致力于构建一个根据 MVC 原则运行并利用依赖注入的 PHP 框架 我想我已经把前端控制器部分放下了 有一个工作路由器实例化控制器实例并根据请求的 URI 调用适当的操作 接下来是依赖注入 我想实现一个使用反射解决依赖关系的容器 这样
  • Java中单例的其他方式[重复]

    这个问题在这里已经有答案了 只是我在考虑编写单例类的其他方法 那么这个类是否被认为是单例类呢 public class MyClass static Myclass myclass static myclass new MyClass pr
  • 这是 C# 的有效、惰性、线程安全的 Singleton 实现吗?

    我实现了这样的单例模式 public sealed class MyClass public static MyClass Instance get return SingletonHolder instance static class
  • 为什么 Google Guice 依赖注入框架有两个单例实例

    我的应用程序中有 2 个 Singleton 实例 都是由 Google Guice 创建的 这怎么可能 绑定完成如下 bind Foo class to FooImpl class in Scopes SINGLETON 这里的问题是绑定
  • 获取Android库中的上下文

    我正在编写一个 Android 应用程序 它的一些功能封装在内部库中 但是 要使此功能发挥作用 库需要一个应用程序上下文的实例 为图书馆提供这种上下文的最佳方式是什么 我看到了一些选择 但没有一个有吸引力 Have my library c
  • 为什么默认构造函数在静态构造函数之前执行?

    我想知道为什么我的静态构造函数会输出default constructor Static Constructor 而不是相反Static Constructor and Default constructor要不就Default const
  • Singleton:是否存在内存泄漏?

    这是一个简单的单例 class Singleton Singleton virtual Singleton Singleton Singleton getInstance static Singleton instance if insta

随机推荐

  • 使用“VMware ThinApp”绿化软件

    当我看到 WPS Office 在我的电脑中写入了上万条注册表项时 我几乎要崩溃了 这个 有点太多了吧 软件绿化工具 环境 Workstation 15 5 Player for Windows 绿化软件 VMware ThinApp 软件
  • 纹波电压

    什么是纹波电压 狭义上的纹波电压 是指输出直流电压中含有的工频交流成分 直流电压本来应该是一个固定的值 但是很多时候它是通过交流电压整流 滤波后得来的 由于滤波不彻底 就会有剩余的交流成分 下图为1 8V的纹波电压 纹波电压是如何产生的 首
  • 2022年Python笔试选择题及答案(秋招)

    2022年Python笔试选择题及答案 秋招 单选题 1 以下关于 Python 的描述错误的是 A Python 的语法类似 PHP B Python 可用于 Web 开发 C Python 是跨平台的 D Python 可用于数据抓取
  • 网络编程day7作业

    将词典导入数据库 include
  • Unity 空格会触发Button的问题

    问题 做了一个界面 空格可以召唤或者关闭一个面板 上面有Button可以控制人物数量信息 当点击过Button修改数量 再按下空格隐藏面板后 最后点击的Button就会被空格键触发一次 如下图 解决 这是由于Button中Navigatio
  • PAT乙级题解—— 1071 小赌怡情 (15分)

    常言道 小赌怡情 这是一个很简单的小游戏 首先由计算机给出第一个整数 然后玩家下注赌第二个整数将会比第一个数大还是小 玩家下注 t 个筹码后 计算机给出第二个数 若玩家猜对了 则系统奖励玩家 t 个筹码 否则扣除玩家 t 个筹码 注意 玩家
  • vue 组件生命周期钩子详解

    Vue是一个自带组件系统的前端框架 Vue的每一个实例其实就是一个组件 我们在组织我们的页面结构的时候其实就是在定一个一个组件 然后拼装在一起 完成一个复杂的页面逻辑 组件主要包含 数据 模版 以及链接数据和模版的状态响应系统 除了这些 我
  • Spark内存管理-UnifiedMemoryManager和StaticMemoryManager

    在Spark 1 6 0中 引入了一个新的参数spark memory userLegacyMode 默认值为false 表示不使用Spark 1 6 0之前的内存管理机制 而是使用1 6 0中引入的动态内存分配这一概念 从SparkEnv
  • 解决Git上传代码error: failed to push some refs to ‘xxx‘hint:(e.g., ‘git pull ...‘) before pushing again错误

    在使用git提交代码时会出现error failed to push some refs to xxxx的错误 如下图 hint Updates were rejected because the remote contains work
  • 使用Adivisor配置增强处理,来实现数据库读写分离

    一 先写一个demo来概述Adivisor的简单使用步骤 实现步骤 1 通过MethodBeforeAdivice接口实现前置增强处理 1 public class ServiceBeforeAdvisor implements Metho
  • 基础算法:前缀和

    前缀和 定义 s i 表示原数组前i个数的和 作用 求任意区间 l r 的和的时间复杂度从循环加的O n 到 s r s l 1 的时间复杂度O 1 eg s 3 a1 a2 a3 s 5 a1 a2 a3 a4 a5 s 4 5 s 5
  • 数字SOC设计之低功耗设计入门(二)——功耗的分析

    前面学习了进行低功耗的目的个功耗的构成 今天就来分享一下功耗的分析 由于是面向数字IC前端设计的学习 所以这里的功耗分析是基于DC中的power compiler工具 更精确的功耗分析可以采用PT 关于PT的功耗分析可以查阅其他资料 这里不
  • Bugku-game WP 一道有意思的题

    开启环境后 进入到了一个页面内的游戏界面 在页面中没有发现什么提示 开始游戏后 发现游戏内玩家通过玩游戏可以获得一定的积分 那么试想是否可以通过将积分更改得很大得做法来通关获得flag 查看源码 众所周知 分数一般会取名为score 那么在
  • Java Web应用开发常用网上资源

    前言 为了方便学习 下面为大家推荐一些学习Java Web开发的相关资源 使用这些资源 可以帮助你找到精通Java Web应用开发的捷径 常用资源下载网 在开发Java Web应用程序时 通常需要到相关资源的官方网站下载一些资源 下面将给出
  • jenkins如何同一jar包部署到多台服务器

    文章目录 安装插件 配置ssh服务 构建完成后执行 没有部署过可以跟这个下面的步骤先部署一遍 我这篇主要讲jenkins同一jar包部署到多台服务器 Jenkins 部署Springboot项目https blog csdn net qq
  • 步进电机五根线怎么接_软启动怎么接电机?软启动电机实物接线图

    电工学习网 www diangon com 关注电工学习网官方微信公众号 电工电气学习 收获更多经验知识 50万 维修电工关注的微信平台 技术分享 学习交流 资料下载 常用的五种电机软启动器 接线图 一 CMC L系列数码型电机软启动器是一
  • 学习笔记 JavaScript ES6 Proxy

    学习内容 代理 常用拦截方法 ES 5当中实现拦截的方法 let obj let newValue Object defineProperty obj name get return newValue set val console log
  • 安卓的多选框CheckBox

    选中选项中的内容并且点击按键 就会在顶头的title显示出来 1 做好布局控件 2 绑定控件 3 button设置了监听 一旦点击了button就跳到checkbox里面去执行 4 checkbox需要if语句进行判断 选中就显示 XML文
  • 你真的知道如何在 ESXi 上安装 Linux 吗?

    1 分区4K对齐以获得最佳存储性能 如果分区没有4K对齐 这对单个磁盘来说不是什么大问题 但对于共享存储来说 共享存储中的一个LUN实际上是跨越多个不同的磁盘条带化的 所以虚拟机操作系统的一次读或写操作会导致存储阵列上的I O翻倍 未对齐的
  • 设计模式(1) 创建型模式和抽象工厂(Abstract Factory)

    问题聚焦 分别用一句话概括这节的几个知识点 什么是创建型模式 抽象了实例化过程 创建型模式有哪些 抽象工厂 工厂方法 原型模式 生成器模式 什么是抽象工厂 AbstractFactory 模式 与接口交互 获得一系列相关或互相依赖的对象实例