设计模式:创建型模式

news2025/1/10 6:18:07

抽象工厂 abstract factory

例子

考虑一个多风格的界面应用,要求可以切换不同风格类型的组件(窗口,滚动条,按钮等)
在这里插入图片描述

风格/组件pm风格motif风格
滚动条pmScrollBarmotifScrollBar
窗口pmWindowMotifWindow

WidgetFactory: 抽象工厂,用于创建滚动条和窗口。

MotifWidgetFactory: 继承抽象工厂(WidgetFactory),用于给Motif类型创建滚动条和窗口。
他依赖于MotifWindow和MotifScrollBar

PMWidgetFactory: 继承抽象工厂(WidgetFactory),用于给PM类型创建滚动条和窗口。
他依赖于PMWindow和PMScrollBar

Client: 客户端,用来操作软件或者系统

结构

在这里插入图片描述
在这里插入图片描述

builder 模式

例子

支持多种格式的富文本阅读器(RTF),比如tex文本,ASCII, WIDGET
在这里插入图片描述
客户端解析文本时,先选择builder,然后根据文本流不同类型,转换不同成不同的格式
比如:tex格式支持复杂的数学公式,只有texbuilder有这个分支

结构

在这里插入图片描述

  1. Builder (TextConverter) 建造者
    specifies an abstract interface for creating parts of a Product object. (为了创建一个对象或者对象的部分而指定一个抽象接口)
  2. ConcreteBuilder (ASCIIConverter, TeXConverter, TextWidgetConverter) 具体建造者
    constructs and assembles parts of the product by implementing the Builder interface. (通过实现建造接口来构建一个产品或者产品的部分)
    defines and keeps track of the representation it creates. (定义并跟踪所创建的表现方式)
    provides an interface for retrieving the product (e.g., GetASCIIText, GetTextWidget). (提供一个获取产品的接口)
  3. Director (RTFReader) 指挥者
    constructs an object using the Builder interface. (用建造接口创建一个对象)
  4. Product (ASCIIText, TeXText, TextWidget) 产品
    represents the complex object under construction. (表示一个正在构建的复杂对象)ConcreteBuilder builds the product’s internal representation and defines the process by which it’s assembled. (具体的建造者构建产品的内部展示,并定义了产品的组装过程)
    includes classes that define the constituent parts (包含构成产品的部件), including interfaces for assembling the parts into the final result. (包含将部件组成最终结果的接口)
    在这里插入图片描述

factory method 工厂方法

未完待续

对比

背景:设计一个迷宫,仅考虑迷宫的构成:由一系列房间,墙,门组成。房间知道邻居是谁:房间,墙或者门。门连接两个房间。忽略所有和游戏者相关的操作:移动,显示等。

定义方向:enum Direction {North,South, East, West}

迷宫组件公共抽象类 MapSite
在这里插入图片描述

不使用设计模式

Class MapSite
{
    public:
        virtual void Enter()=0;
};

class Room : public MapSite { 
	public : 
		Room (int roomNo) 
		MapSite* GetSide (Direction) const; 
		void SetSide (Direction, Mapsite*); 
		virtual void Enter() 
	private: 
		MapSite* _sides[4] ; 
		int _roomNumber; 
};

class Wall : public MapSite { 
	public : 
		Wall();
		virtual void Enter( ) ;
};
class Door public Mapsite { 
	public : 
		Door (Room* = 0, Room* = 0) ; 
		virtual void Enter ( ) 
		Room* OtherSideFrom (Room* ) ;
	
	private :
		Room* _room1;
		Room* _room2;
		bool _isOpen ; 
} ;

class Maze 
{
	Public:
		Maze ; 
		void AddRoom (Room* ) ; 
		Room* RoomNo ( int) const ; 
	private: 
//…
};


//创建迷宫 
Maze *MazeGame()
{
	Maze* aMaze =new Maze;
	Room *r1 = new Room(1);
	Room *r2 = new Room(2);
	Door theDoor = new Door(r1,r2);
	aMaze ->AddRoom(r1);
	aMaze ->AddRoom(r2);
	r1->SetSide(North, new Wall);
	r1->SetSide(South, theDoor );
	r1->SetSide(East,  new Wall);
	r1->SetSide(West, new Wall);
	r2 ->SetSide(North, new Wall);
	r2 ->SetSide(South,  new Wall);
	r2 ->SetSide(East,  new Wall);
	r2 ->SetSide(West, theDoor );
	return aMaze;
}

抽象工厂


 class MazeFactory ( 
public
	MazeFactory ( ) ; 
	virtual Maze* MakeMaze() const 
	{return new Maze; }
	virtual Wall* MakeWall() const 
	{return new Wall; }
	virtual Room* MakeRoom(int n) const 
	{return new Room(n)} )
	virtual Door* MakeDoor ( Room* r1, Room* r2)  const
	{return new Door (rl, r2); }
}

 class BombedMazeFactory  : public MazeFactory( 
public
	BombedMazeFactory ( ) ; 
	virtual Maze* MakeMaze() const 
	{return new Maze; }
	virtual Wall* MakeWall() const 
	{return new BombedWall; }
	virtual Room* MakeRoom(int n) const 
	{return new BombedRoom(n)} )
	virtual Door* MakeDoor ( Room* r1, Room* r2)  const
	{return new BombedDoor (rl, r2); }
}


Maze *MazeGame:: CreateMaze(MazeFactory & factory)
{
	Maze* aMaze =factory. MakeMaze() ;
	Room *r1 = factory. MakeRoom(1) ;
	Room *r2 =factory. MakeRoom(2) ;
	Door theDoor = factory.MakeDoor(r1,r2);
	aMaze ->AddRoom(r1);
	aMaze ->AddRoom(r2);
	r1->SetSide(North, factory.MakeWall() );
	r1->SetSide(South, theDoor );
	r1->SetSide(East,   factory.MakeWall() );
	r1->SetSide(West,  factory.MakeWall() );
	r2 ->SetSide(North,  factory.MakeWall() );
	r2 ->SetSide(South,   factory.MakeWall() );
	r2 ->SetSide(East,   factory.MakeWall() );
	r2 ->SetSide(West, theDoor );
	return aMaze;
}


builder

Builder 模式

class MazeBuilder { 
	public: 
		virtual void BuildMaze (){}
		virtual void BuildRoom (int room) { } 
		virtual void BuildDoor (int roomFrom. int roomTo ) { } 
		virtual Maze* GetMaze () { return 0 ; } 
	protectedMazeBuiIder();
};

该 接 口 可 以 创 建 : 1 ) 迷 宫 。 2 ) 有 一 个 特 定 房 间 号 的 房 间 。 3 ) 在 有 号 码 的 房 间 之 间 的 门 。
GetMaze 操 作 返 回 这 个 迷 宫 给 客 户 。 MazeBu11der 的 子 类 将 重 定 义 这 些 操 作 , 返 回 它 们 所 创 建
的 迷 宫 。

不定义为纯虚函数,是为了方便派生类只重定义它们感兴趣的接口

用 MazeBuilder 接 口 , 我 们 可 以 改 变 createMaze 成 员 函 数 , 以 生 成 器 作 为 它 的 参 数 。

Maze* MazeGame ::CreateMaze (MazeBuilder & builder)
 { 
	builder.BuildMaze(); 
	builder.BuildRoom(1); 
	builder.BuildRoom(2); 
	builder.BuildDoor(1,2) ;
	return builder.GetMaze()}

将 这 个 createMaze 版 本 与 原 来 的 相 比 , 注 意 生 成 器 是 如 何 隐 藏 迷 宫 的 内 部 表 示 的 一 一 一 即 定
义 房 间 、 门 和 墙 壁 的 那 些 类 . 一 一 以 及 这 些 部 件 是 如 何 组 装 成 最 终 的 迷 宫 的 。 有 人 可 能 猜 测 到
有 一 些 类 是 用 来 表 示 房 间 和 门 的 , 但 没 有 迹 象 显 示 哪 个 类 是 用 来 表 示 墻 壁 的 。 这 就 使 得 改 变
一 个 迷 宫 的 表 示 方 式 要 容 易 一 些 , 因 为 所 有 MazeBuiIder 的 客 户 都 不 需 要 被 改 变 。

MazeBuilder自己并不创建迷宫,子 类 做 实 际 工 作:
子 类 StandardMazeBuilder :一 个 创 建 简 单 迷 宫 的 实 现 。 它 将 它 正 在 创 建 的 迷 宫 放 在 变 量 _currentMaze 中 。

class StandardMazeBuiIder : public MazeBuilder
{ 
	Public:
		StandardMazeBuilder(){ _currentMaze=0}; 
		virtual void BuildMaze (){  _currentMaze = new Maze;}
		virtual void BuildRoom (int room) { } 
		virtual void BuildDoor (int roomFrom. int roomTo ) { } 
		virtual Maze* GetMaze ()return _currentMaze; } 
	Private:
		Direction CommonWall( room*, Room*);
		 Maze* _currentMaze;
}

//创造一个都是墙的房间
void StandardMazeBuilder :: BuildRoom (int n) 
{
	if (! _currentMaze—>RoomNo (n)) 
	{ 
		Room room =new Room(n);
		 _currentMaze->AddRoom(room); 
		room->SetSide (North, new  Wall); 
		room->SetSide(South, new Wall); 
		room->SetSide(East, new Wall);  
		room->SetSide(West, nev Wall);
	}
}

//建造一扇两个房间之间的门,其中CommonWall找到两个房间相邻的墙壁
Void StandardMazeBuilder::BuildDoor(int n1, int n2)
{
	Room* r1 =  _currentMaze->RoomNo(n1);
	Room* r2 =  _currentMaze->RoomNo(n2);
	Door *d = new Door(r1,r2);
	r1->SetSide(CommonWall(r1,r2) , d);
	r1->SetSide(CommonWall(r2,r1) , d);
}
现在客户可以创建迷宫了
Maze* maze; 
MazeGame game; 
StandardMazeBuiIder builder ; 
game. CreateMaze (builder) 
Maze= builder.GetMaze(); 

我 们 本 可 以 将 所 有 的 standardMazeBuiIderN 作 放 在 Maze 中 并 让 每 一 个 Maze 创 建 它 自 身 。
但 将 Maze 变 得 小 一 些 使 得 它 能 更 容 易 被 理 解 和 修 改 , 而 且 standardMazeBuiIder 易 于 从 Maze 中
分 离 。 更 重 要 的 是 , 将 两 者 分 离 使 得 你 可 以 有 多 种 MazeB 回 der , 每 一 种 使 用 不 同 的 房 间 、 墙
壁 和 门 的 类 。

对比

抽象工厂模式强调的是创造不同系列的产品,所以每个产品都有一个抽象类,比如window。而builder模式中,可能无法抽取公共产品抽象类,它更强调产品的构建方式,所以void StandardMazeBuilder :: BuildRoom (int n) 中直接定义了房间是怎么构建的,而在抽象工厂模式这个过程不在MazeFactory 里面而在Maze *MazeGame:: CreateMaze(MazeFactory & factory)函数里,也就是说MazeFactory 只负责创建不同类型的产品,客户负责组装;Builder 则自己组装想要的产品,客户直接拿

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

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

相关文章

Vue中TodoList案例_静态

MyHeader.vue <template><div class"todo-header"><input type"text" placeholder"请输入你的任务名称&#xff0c;按回车键确认"></div> </template><script> export default {name: "MyHeader"…

16. python从入门到精通——Python网络爬虫

目录 什么是爬虫 优点 网络爬虫的常用技术 网络请求&#xff1a;有三个常用网络请求模块 Urllib模块&#xff1a;python原生系统中标准库模块 urllib中的子模块 urllib.parse.urlencode() 常用于进行 URL 的 get 请求参数拼接 Urllib3模块&#xff1a;Urllib模块的升级版…

paramiko模块使用(2)

远程查看服务器资源使用情况 单机实现 import paramiko# 定义远程服务器的连接信息 hostname 192.168.2.198 username root password 123456# 创建SSH客户端对象 client paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy())try:# 连接到…

力扣刷题SQL-197. 上升的温度---分步解题

表&#xff1a; Weather ------------------------ | Column Name | Type | ------------------------ | id | int | | recordDate | date | | temperature | int | ------------------------ id 是这个表的主键 该表包含特定日期的温度信息编…

qemu搭建arm环境以及文件共享

几乎完全参照该文章 使用QEMU搭建ARM64实验环境 - 简书 ubuntu 14.04&#xff0c;linux3.16&#xff0c; busybox-1.31.0 arm-linux-gnueabi-gcc -v linux3.16以及busybox下载安装可参考链接 Ubuntu14.04安装qemu&#xff0c;运行linux-3.16gdb调试_qemu 安装 ubuntu 14_这个我…

项目开启启动命令整合

启动RabbitMQ管理插件 1.启动 RabbitMQ 管理插件。 rabbitmq-plugins enable rabbitmq_management rabbitmq-server # 直接启动&#xff0c;如果关闭窗⼝或需要在该窗⼝使⽤其他命令时应⽤就会停⽌ rabbitmq-server -detached # 后台启动 rabbitmq-server start # 启⽤服务 rab…

【亲测可用】安装Qt提示“无法下载存档 http://download.qt.io/online/qtsdkrepository...“

下载Qt安装程序exe之后&#xff0c;一般直接双击运行然后&#xff0c;注册登录后&#xff0c;到了第三步【安装程序】时&#xff0c;进行远程检索文件总会卡在这里&#xff0c;无法进行到下一步。报错如下&#xff1a; 解决办法&#xff1a; 关闭安装程序&#xff0c;然后&…

一百三十二、ClickHouse——ClickHouse建表时默认字段非空导致数据问题

一、ClickHouse建表问题 由于ClickHouse建表时默认字段非空 &#xff08;一&#xff09;建表语句 &#xff08;二&#xff09;查看字段属性 ClickHouse建表时一般情况下直接默认字段非空 &#xff08;三&#xff09;导致问题 所以这就导致一般情况下&#xff0c;一些字段的…

iphone新机官网验机流程

苹果官网验机流程 进入苹果官网&#xff0c;找到技术支持&#xff0c;进入“查看保障服务和支持期限“页面&#xff0c;输入要查询的机器的序列号&#xff0c;就可以查询了。 苹果官网验机入口&#xff1a;https://checkcoverage.apple.com/ 输入iphone序列号进行验机&#xff…

小程序体验版上线注意事项

1.接口域名必须是https&#xff0c;有ssh证书。不能用ip地址。 2.需要在微信公众平台进行配置 微信公众平台->开发-> 开发管理->开发设置 对服务器域名和业务域名进行配置对业务域名进行配置时&#xff0c;需要下载校验文件&#xff0c;放在域名根目录下

力扣刷题27.移除元素(Accept03)

力扣刷题 代码随想录数组 3.移除元素 力扣27. 移除元素 方法一&#xff1a;暴力解决法 1. 思路 两层嵌套循环遍历数组&#xff0c;内层循环主要是当第一层循环遍历到的元素等于要移除的元素的值的时候&#xff0c;其后的元素依次向前挪动一个位置&#xff08;覆盖要删除的…

计科web常见错误排错【HTTP状态404、导航栏无法点开、字符乱码及前后端数据传输呈现、jsp填写的数据传到数据库显示null、HTTP状态500】

web排错记录 在使用javaweb的过程中会出现的一些错误请在下方目录查找。 目录 错误1&#xff1a;HTTP状态404——未找到 错误2&#xff1a;导航栏下拉菜单无法点开的问题 错误3&#xff1a;字符乱码问题 错误4&#xff1a;jsp网页全部都是&#xff1f;&#xff1f;&#x…

科技云报道:边缘云赛道开启,谁能成为首个“出线”厂商?

科技云报道原创。 每一轮底层技术变革&#xff0c;都会带来全新的商业机遇。随着万物智联时代到来&#xff0c;大量数据产生的源头由传统的中心化向分散数据源变革&#xff0c;越来越多云边协同场景的出现&#xff0c;使得边缘云成为计算领域数据处理的新范式之一。 自2020年…

CHI协议保序之Compack保序

一致性系统中&#xff0c;使用三种保序方式&#xff1b; Completion ack response ⭕Completion acknowledgment&#xff1a; □ 该域段主要是用来&#xff0c; □ 决定 RN 发送的 trans&#xff0c;与其他 RN 发送的命令产生的 SNP 之间的顺序&#xff1b; …

[VUE]Element_UI 实现TreeSelect 树形选择器

文章目录 前言1、安装2、引用3、使用 前言 最近在做一个人员管理系统&#xff0c;在增改用户信息时&#xff0c;可能会设置用户所在的部门&#xff0c;因为部门是多级的&#xff0c;于是想到用Element_UI的TreeSelect组件实现 效果&#xff1a; 1、安装 npm install --save…

蓝桥杯专题-真题版含答案-【牌型种数】【煤球数目】【寒假作业】【奖券数目】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

如何动态修改 spring aop 切面信息?让自动日志输出框架更好用

业务背景 很久以前开源了一款 auto-log 自动日志打印框架。 其中对于 spring 项目&#xff0c;默认实现了基于 aop 切面的日志输出。 但是发现一个问题&#xff0c;如果切面定义为全切范围过大&#xff0c;于是 v0.2 版本就是基于注解 AutoLog 实现的。 只有指定注解的类或…

pytest常用执行参数详解

1. 查看pytest所有可用参数 我们可以通过pytest -h来查看所有可用参数。 从图中可以看出&#xff0c;pytest的参数有很多&#xff0c;下面是归纳一些常用的参数&#xff1a; -s&#xff1a;输出调试信息&#xff0c;包括print打印的信息。-v&#xff1a;显示更详细的信息。…

GAN在图像超分辨领域的应用

本篇博客介绍了对抗生成网络GAN在图像超分辨领域的应用&#xff0c;包括(SRGAN, ESRGAN, BSRGAN, Real-ESRGAN),详细介绍了论文内容&#xff0c;方法&#xff0c;网络结构并对其做了相关总结。相关GAN原理的介绍大家可以查看我之前的几篇博客&#xff0c;链接如下&#xff1a;生…

从用户的角度谈GPT时代技术突破的两大关键逻辑

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…