用户名
Email
论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
朋友圈
看朋友圈动态,了解ToB世界。
ToB门户
了解全球最新的ToB事件
博客
Blog
排行榜
Ranklist
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
导读
Guide
相册
Album
记录
Doing
帖子
本版
文章
帖子
ToB圈子
用户
免费入驻
产品入驻
解决方案入驻
公司入驻
案例入驻
登录
·
注册
只需一步,快速开始
账号登录
立即注册
找回密码
用户名
自动登录
找回密码
密码
登录
立即注册
首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
圈子
SAAS
IT评测·应用市场-qidao123.com
»
论坛
›
数据库
›
Oracle
›
设计模式-对象创建
设计模式-对象创建
反转基因福娃
论坛元老
|
2025-3-18 05:32:35
|
来自手机
|
显示全部楼层
|
阅读模式
楼主
主题
1008
|
帖子
1008
|
积分
3024
前言
“对象创建”模式:
通过“对象创建” 模式绕开new,来制止对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。
典型模式:
Factory Method 工厂方法
Abstract Factory 抽象工厂
Prototype
Builder
1. Factory Method
1.1 模式介绍
动机:
在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。
如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来制止客户程序和这种“具体对象创建工作”的紧耦合?
界说一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类。
——《设计模式》GoF
1.2 模式代码
1.2.1 问题代码
class ISplitter{
public:
virtual void split()=0;
virtual ~ISplitter(){}
};
class BinarySplitter : public ISplitter{
};
class TxtSplitter: public ISplitter{
};
class PictureSplitter: public ISplitter{
};
class VideoSplitter: public ISplitter{
};
class MainForm : public Form
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;
public:
void Button1_Click(){
ISplitter * splitter=
new BinarySplitter();//依赖具体类
splitter->split();
}
};
复制代码
你有一个按钮,点击按钮以后可以对二进制文件、文本文件、图片文件、视频文件举行分割,如果按照上述代码举行编写,其依赖具体类,如果你想增加其他文件格式方法时,得修改button里的方法,这会使得封装性被粉碎
1.2.2 重构代码
//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ~ISplitter(){}
};
//工厂基类
class SplitterFactory{
public:
virtual ISplitter* CreateSplitter()=0;
virtual ~SplitterFactory(){}
};
//具体类
class BinarySplitter : public ISplitter{
virtual void split()
{}
};
class TxtSplitter: public ISplitter{
virtual void split()
{}
};
class PictureSplitter: public ISplitter{
virtual void split()
{}
};
class VideoSplitter: public ISplitter{
virtual void split()
{}
};
//具体工厂
class BinarySplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new BinarySplitter();
}
};
class TxtSplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new TxtSplitter();
}
};
class PictureSplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new PictureSplitter();
}
};
class VideoSplitterFactory: public SplitterFactory{
public:
virtual ISplitter* CreateSplitter(){
return new VideoSplitter();
}
};
class MainForm : public Form
{
SplitterFactory* factory;//工厂
public:
MainForm(SplitterFactory* factory){
this->factory=factory;
}
void Button1_Click(){
ISplitter * splitter=
factory->CreateSplitter(); //多态new
splitter->split();
}
};
复制代码
解决方法:设计一个工厂基类,声明一个创建对象的接口,对象底子工厂基类,实现创建对象的方法,即可实现运行时绑定
1.3 模式类图
1.4 要点总结
Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱。
Factory Method模式通过面向对象的本领,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。
Factory Method模式解决“单个对象”的需求变化。缺点在于要求创建方法/参数相同。
2. Abstract Factory
2.1 模式介绍
动机:在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,每每存在更多系列对象的创建工作。
如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来制止客户程序和这种“多系列具体对象创建工作”的紧耦合?
提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。
——《设计模式》GoF
2.2 模式代码
抽象工厂是工厂方法模式的子集,当要创建的对象之间有关联时才使用抽象工厂
2.2.1 问题代码
假设现在要实现SQL处理的功能
问题代码1:直接将类型硬编码到功能里,如果有多种数据库,比如MySQL、Oracle等等,就会不利于扩展
class EmployeeDAO{
public:
vector<EmployeeDO> GetEmployees(){
SqlConnection* connection =
new SqlConnection();
connection->ConnectionString = "...";
SqlCommand* command =
new SqlCommand();
command->CommandText="...";
command->SetConnection(connection);
SqlDataReader* reader = command->ExecuteReader();
while (reader->Read()){
}
}
};
复制代码
问题代码2:在问题代码1的底子上,使用工厂方法解决依赖具体类问题
//数据库访问有关的基类
class IDBConnection{
};
class IDBConnectionFactory{
public:
virtual IDBConnection* CreateDBConnection()=0;
};
class IDBCommand{
};
class IDBCommandFactory{
public:
virtual IDBCommand* CreateDBCommand()=0;
};
class IDataReader{
};
class IDataReaderFactory{
public:
virtual IDataReader* CreateDataReader()=0;
};
//支持SQL Server
class SqlConnection: public IDBConnection{
};
class SqlConnectionFactory:public IDBConnectionFactory{
};
class SqlCommand: public IDBCommand{
};
class SqlCommandFactory:public IDBCommandFactory{
};
class SqlDataReader: public IDataReader{
};
class SqlDataReaderFactory:public IDataReaderFactory{
};
//支持Oracle
class OracleConnection: public IDBConnection{
};
class OracleCommand: public IDBCommand{
};
class OracleDataReader: public IDataReader{
};
class EmployeeDAO{
IDBConnectionFactory* dbConnectionFactory;
IDBCommandFactory* dbCommandFactory;
IDataReaderFactory* dataReaderFactory;
public:
vector<EmployeeDO> GetEmployees(){
IDBConnection* connection =
dbConnectionFactory->CreateDBConnection();
connection->ConnectionString("...");
IDBCommand* command =
dbCommandFactory->CreateDBCommand();
command->CommandText("...");
command->SetConnection(connection); //关联性
IDBDataReader* reader = command->ExecuteReader(); //关联性
while (reader->Read()){
}
}
};
复制代码
如果转达的dbConnectionFactory、dbCommandFactory、dataReaderFactory不是同一系列的就会出问题,比方一部分是MySQL对象,一部分是Oracle对象
2.2.2 重构代码
//数据库访问有关的基类
class IDBConnection{
};
class IDBCommand{
};
class IDataReader{
};
class IDBFactory{
public:
virtual IDBConnection* CreateDBConnection()=0;
virtual IDBCommand* CreateDBCommand()=0;
virtual IDataReader* CreateDataReader()=0;
};
//支持SQL Server
class SqlConnection: public IDBConnection{
};
class SqlCommand: public IDBCommand{
};
class SqlDataReader: public IDataReader{
};
class SqlDBFactory:public IDBFactory{
public:
virtual IDBConnection* CreateDBConnection()=0;
virtual IDBCommand* CreateDBCommand()=0;
virtual IDataReader* CreateDataReader()=0;
};
//支持Oracle
class OracleConnection: public IDBConnection{
};
class OracleCommand: public IDBCommand{
};
class OracleDataReader: public IDataReader{
};
class EmployeeDAO{
IDBFactory* dbFactory;
public:
vector<EmployeeDO> GetEmployees(){
IDBConnection* connection =
dbFactory->CreateDBConnection();
connection->ConnectionString("...");
IDBCommand* command =
dbFactory->CreateDBCommand();
command->CommandText("...");
command->SetConnection(connection); //关联性
IDBDataReader* reader = command->ExecuteReader(); //关联性
while (reader->Read()){
}
}
};
复制代码
将一系列方法封装在一起,这便是抽象工厂模式
2.3 模式类图
2.4 要点总结
如果没有应对“多系列对象构建”的需求变化,则没有必要使用Abstract Factory模式,这时候使用简朴的工厂完全可以。
“系列对象”指的是在某一特定系列下的对象之间有相互依赖、或作用的关系。不同系列的对象之间不能相互依赖。
Abstract Factory模式重要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。
3. Prototype
3.1 模式介绍
原型是一种创建型设计模式,它允许您复制现有对象,而不使您的代码依赖于它们的类。
问题:
假设你有一个对象,你想创建它的一个精确副本。你会怎么做?首先,你必须创建一个相同类的新对象。然后你必须遍历原始对象的所有字段并将其值复制到新对象。
很好!但是有一个问题。并非所有对象都可以通过这种方式复制,由于某些对象的字段可能是私有的,从对象自己外部不可见。
直接方法还有一个问题。由于您必须知道对象的类才能创建副本,因此您的代码将依赖于该类。如果额外的依赖关系不吓到您,那么还有另一个问题。偶然您只知道对象遵循的接口,但不知道其具体类,比方,当方法中的参数接受遵循某个接口的任何对象时。
3.2 模式代码
//抽象类
class ISplitter{
public:
virtual void split()=0;
virtual ISplitter* clone()=0; //通过克隆自己来创建对象
virtual ~ISplitter(){}
};
//具体类
class BinarySplitter : public ISplitter{
public:
virtual ISplitter* clone(){
return new BinarySplitter(*this);
}
virtual void split()
{}
};
class TxtSplitter: public ISplitter{
public:
virtual ISplitter* clone(){
return new TxtSplitter(*this);
}
virtual void split()
{}
};
class PictureSplitter: public ISplitter{
public:
virtual ISplitter* clone(){
return new PictureSplitter(*this);
}
virtual void split()
{}
};
class VideoSplitter: public ISplitter{
public:
virtual ISplitter* clone(){
return new VideoSplitter(*this);
}
virtual void split()
{}
};
class MainForm : public Form
{
ISplitter* prototype;//原型对象
public:
MainForm(ISplitter* prototype){
this->prototype=prototype;
}
void Button1_Click(){
ISplitter * splitter=
prototype->clone(); //克隆原型
splitter->split();
}
};
复制代码
3.3 模式类图
3.4 要点总结
您可以克隆对象而不与其具体类耦合。
您可以摆脱重复的初始化代码,转而克隆预先构建的原型。
您可以更加方便地制作复杂的物体。
处理复杂对象的设置预设时,您可以得到继承的替换方法。
4. Builder
4.1 模式介绍
动机:在软件系统中,偶然候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?
将一个复杂对象的构建与其表示相分离,使得同样的构建过程(稳定)可以创建不同的表示(变化)。
——《设计模式》GoF
4.2 模式代码
class House{
//....
};
class HouseBuilder {
public:
House* GetResult(){
return pHouse;
}
virtual ~HouseBuilder(){}
protected:
House* pHouse;
virtual void BuildPart1()=0;
virtual void BuildPart2()=0;
virtual void BuildPart3()=0;
virtual void BuildPart4()=0;
virtual void BuildPart5()=0;
};
class StoneHouse: public House{
};
class StoneHouseBuilder: public HouseBuilder{
protected:
virtual void BuildPart1(){
//pHouse->Part1 = ...;
}
virtual void BuildPart2(){
}
virtual void BuildPart3(){
}
virtual void BuildPart4(){
}
virtual void BuildPart5(){
}
};
class HouseDirector{
public:
HouseBuilder* pHouseBuilder;
HouseDirector(HouseBuilder* pHouseBuilder){
this->pHouseBuilder=pHouseBuilder;
}
House* Construct(){
pHouseBuilder->BuildPart1();
for (int i = 0; i < 4; i++){
pHouseBuilder->BuildPart2();
}
bool flag=pHouseBuilder->BuildPart3();
if(flag){
pHouseBuilder->BuildPart4();
}
pHouseBuilder->BuildPart5();
return pHouseBuilder->GetResult();
}
};
复制代码
构建器HouseBuilder负责界说构建House时每个步调的具体接口(变化)和管理正在构建的对象,由子类继承并实现接口;
HouseDirector负责实现House在构建时的整体流程(不变)
4.3 模式类图
4.4 要点总结
Builder 模式重要用于“分步调构建一个复杂的对象”。在这其中“分步调”是一个稳定的算法,而复杂对象的各个部分则经常变化。
变化点在哪里,封装哪里—— Builder模式重要在于应对“复杂对象各个部分”的频繁需求变动。其缺点在于难以应对“分步调构建算法”的需求变动。
在Builder模式中,要注意不同语言中构造器内调用虚函数的差异(C++ vs. C#) 。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
本帖子中包含更多资源
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
回复
举报
0 个回复
倒序浏览
返回列表
快速回复
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
or
立即注册
本版积分规则
发表回复
回帖并转播
回帖后跳转到最后一页
发新帖
回复
反转基因福娃
论坛元老
这个人很懒什么都没写!
楼主热帖
设计模式---组合模式
Spark快速上手(4)Spark核心编程-Spark ...
【Unity3D】Transform组件
拿到12家offer,想给大家分享一下面试 ...
【渗透攻击】PowerShell与Shell 有什么 ...
echarts使用及遇到的问题
使用 Kubeadm 部署 K8S安装
软件工程经济学第一章
如何将鸿蒙(harmonyOS)系统退回安卓 ...
Linux的目录结构
标签云
运维
CIO
存储
服务器
浏览过的版块
移动端开发
快速回复
返回顶部
返回列表