目录
7. 原型模式
原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。通俗的讲就是当需要创建一个新的实例化对象时,我们刚好有一个实例化对象,但是已经存在的实例化对象又不能直接使用。这种情况下拷贝一个现有的实例化对象来用,可能会更方便。
以下情形可以考虑使用原型模式:
1. 当new一个对象,非常繁琐复杂时,可以使用原型模式来进行复制一个对象。比如创建对象时,构造函数的参数很多,而自己又不完全的知道每个参数的意义,就可以使用原型模式来创建一个新的对象,不必去理会创建的过程。
2. 当需要new一个新的对象,这个对象和现有的对象区别不大,我们就可以直接复制一个已有的对象,然后稍加修改。
3. 当需要一个对象副本时,比如需要提供对象的数据,同时又需要避免外部对数据对象进行修改,那就拷贝一个对象副本供外部使用。
/*
* 关键代码:拷贝,return new className(*this);
*/
#include <iostream>
using namespace std;
//提供一个抽象克隆基类。
class Clone
{
public:
virtual Clone* clone() = 0;
virtual void show() = 0;
};
//具体的实现类
class Sheep:public Clone
{
public:
Sheep(int id, string name):Clone(),m_id(id),m_name(name)
{
cout << "Sheep() id address:" << &m_id << endl;
cout << "Sheep() name address:" << &m_name << endl;
}
~Sheep()
{
}
//关键代码拷贝构造函数
Sheep(const Sheep& obj)
{
this->m_id = obj.m_id;
this->m_name = obj.m_name;
cout << "Sheep(const Sheep& obj) id address:" << &m_id << endl;
cout << "Sheep(const Sheep& obj) name address:" << &m_name << endl;
}
//关键代码克隆函数,返回return new Sheep(*this)
Clone* clone()
{
return new Sheep(*this);
}
void show()
{
cout << "id :" << m_id << endl;
cout << "name:" << m_name.data() << endl;
}
private:
int m_id;
string m_name;
};
int main()
{
Clone* s1 = new Sheep(1, "abs");
s1->show();
Clone* s2 = s1->clone();
s2->show();
delete s1;
s1 = nullptr;
delete s2;
s2 = nullptr;
return 0;
}
7.1 实例2
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。其中有一个词很重要,那就是拷贝。可以说,拷贝是原型模式的精髓所在。举个现实中的例子来介绍原型模式。找工作的时候,我们需要准备简历。假设没有打印设备,因此需手写简历,这些简历的内容都是一样的。这样有个缺陷,如果要修改简历中的某项,那么所有已写好的简历都要修改,工作量很大。随着科技的进步,出现了打印设备。我们只需手写一份,然后利用打印设备复印多份即可。如果要修改简历中的某项,那么修改原始的版本就可以了,然后再复印。原始的那份手写稿相当于是一个原型,有了它,就可以通过复印(拷贝)创造出更多的新简历。这就是原型模式的基本思想。下面给出原型模式的UML图,以刚才那个例子为实例。
原型模式实现的关键就是实现Clone函数,对于C++来说,其实就是拷贝构造函数,需实现深拷贝,下面给出一种实现。
//父类
class Resume
{
protected:
char *name;
public:
Resume() {}
virtual ~Resume() {}
virtual Resume* Clone() { return NULL; }
virtual void Set(char *n) {}
virtual void Show() {}
};
class ResumeA : public Resume
{
public:
ResumeA(const char *str); //构造函数
ResumeA(const ResumeA &r); //拷贝构造函数
~ResumeA(); //析构函数
ResumeA* Clone(); //克隆,关键所在
void Show(); //显示内容
};
ResumeA::ResumeA(const char *str)
{
if(str == NULL) {
name = new char[1];
name[0] = '\0';
}
else {
name = new char[strlen(str)+1];
strcpy(name, str);
}
}
ResumeA::~ResumeA() { delete [] name;}
ResumeA::ResumeA(const ResumeA &r) {
name = new char[strlen(r.name)+1];
strcpy(name, r.name);
}
ResumeA* ResumeA::Clone() {
return new ResumeA(*this);
}
void ResumeA::Show() {
cout<<"ResumeA name : "<<name<<endl;
}
ResumeB的实现类似(不再给出)。使用的方式如下:
int main()
{
Resume *r1 = new ResumeA("A");
Resume *r2 = new ResumeB("B");
Resume *r3 = r1->Clone();
Resume *r4 = r2->Clone();
r1->Show(); r2->Show();
//删除r1,r2
delete r1; delete r2;
r1 = r2 = NULL;
//深拷贝所以对r3,r4无影响
r3->Show(); r4->Show();
delete r3; delete r4;
r3 = r4 = NULL;
}
参考资料:https://blog.csdn.net/wuzhekai1985/article/details/6667020
参考资料:https://www.cnblogs.com/chengjundu/p/8473564.html
8. 模板模式
模板模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
当多个类有相同的方法,并且逻辑相同,只是细节上有差异时,可以考虑使用模板模式。具体的实现上可以将相同的核心算法设计为模板方法,具体的实现细节有子类实现。
缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
例子:以生产电脑为例,电脑生产的过程都是一样的,只是一些装配的器件可能不同而已。
/*
* 关键代码:在抽象类实现通用接口,细节变化在子类实现。
*/
#include <iostream>
using namespace std;
class Computer
{
public:
void product()
{
installCpu();
installRam();
installGraphicsCard();
}
protected:
virtual void installCpu() = 0;
virtual void installRam() = 0;
virtual void installGraphicsCard() = 0;
};
class ComputerA : public Computer
{
protected:
void installCpu() override
{
cout << "ComputerA install Inter Core i5" << endl;
}
void installRam() override
{
cout << "ComputerA install 2G Ram" << endl;
}
void installGraphicsCard() override
{
cout << "ComputerA install Gtx940 GraphicsCard" << endl;
}
};
class ComputerB : public Computer
{
protected:
void installCpu() override
{
cout << "ComputerB install Inter Core i7" << endl;
}
void installRam() override
{
cout << "ComputerB install 4G Ram" << endl;
}
void installGraphicsCard() override
{
cout << "ComputerB install Gtx960 GraphicsCard" << endl;
}
};
int main()
{
ComputerB* c1 = new ComputerB();
c1->product();
delete c1;
c1 = nullptr;
return 0;
}
8.1 实例1
最近有个招聘会,可以带上简历去应聘了。但是,其中有一家公司不接受简历,而是给应聘者发了一张简历表,上面有基本信息、教育背景、工作经历等栏,让应聘者按照要求填写完整。每个人拿到这份表格后,就开始填写。如果用程序实现这个过程,该如何做呢?一种方案就是用模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。我们的例子中,操作就是填写简历这一过程,我们可以在父类中定义操作的算法骨架,而具体的实现由子类完成。下面给出它的UML图。
其中FillResume() 定义了操作的骨架,依次调用子类实现的函数。相当于每个人填写简历的实际过程。接着给出相应的C++代码。
//简历
class Resume
{
protected: //保护成员
virtual void SetPersonalInfo() {}
virtual void SetEducation() {}
virtual void SetWorkExp() {}
public:
void FillResume()
{
SetPersonalInfo();
SetEducation();
SetWorkExp();
}
};
class ResumeA: public Resume
{
protected:
void SetPersonalInfo() { cout<<"A's PersonalInfo"<<endl; }
void SetEducation() { cout<<"A's Education"<<endl; }
void SetWorkExp() { cout<<"A's Work Experience"<<endl; }
};
class ResumeB: public Resume
{
protected:
void SetPersonalInfo() { cout<<"B's PersonalInfo"<<endl; }
void SetEducation() { cout<<"B's Education"<<endl; }
void SetWorkExp() { cout<<"B's Work Experience"<<endl; }
};
使用方式如下:
int main()
{
Resume *r1;
r1 = new ResumeA();
r1->FillResume();
delete r1;
r1 = new ResumeB();
r1->FillResume();
delete r1;
r1 = NULL;
return 0;
}
参考资料:https://blog.csdn.net/wuzhekai1985/article/details/6667020
参考资料:https://www.cnblogs.com/chengjundu/p/8473564.html
9. 建造者模式
建造者模式:将复杂对象的构建和其表示分离,使得相同的构建过程可以产生不同的表示。
以下情形可以考虑使用建造者模式:
1. 对象的创建复杂,但是其各个部分的子对象创建算法一定。
2. 需求变化大,构造复杂对象的子对象经常变化,但将其组合在一起的算法相对稳定。
建造者模式的优点:
1. 将对象的创建和表示分离,客户端不需要了解具体的构建细节。
2. 增加新的产品对象时,只需要增加其具体的建造类即可,不需要修改原来的代码,扩展方便。
产品之间差异性大,内部变化较大、较复杂时不建议使用建造者模式。
/*
*关键代码:建造者类:创建和提供实例; Director类:管理建造出来的实例的依赖关系。
*/
#include <iostream>
#include <string>
using namespace std;
//具体的产品类
class Order
{
public:
void setFood(const string& food)
{
m_strFood = food;
}
const string& food()
{
cout << m_strFood.data() << endl;
return m_strFood;
}
void setDrink(const string& drink)
{
m_strDrink = drink;
}
const string& drink()
{
cout << m_strDrink << endl;
return m_strDrink;
}
private:
string m_strFood;
string m_strDrink;
};
//抽象建造类,提供建造接口。
class OrderBuilder
{
public:
virtual ~OrderBuilder()
{
cout << "~OrderBuilder()" << endl;
}
virtual void setOrderFood() = 0;
virtual void setOrderDrink() = 0;
virtual Order* getOrder() = 0;
};
//具体的建造类
class VegetarianOrderBuilder : public OrderBuilder
{
public:
VegetarianOrderBuilder()
{
m_pOrder = new Order;
}
~VegetarianOrderBuilder()
{
cout << "~VegetarianOrderBuilder()" << endl;
delete m_pOrder;
m_pOrder = nullptr;
}
void setOrderFood() override
{
m_pOrder->setFood("vegetable salad");
}
void setOrderDrink() override
{
m_pOrder->setDrink("water");
}
Order* getOrder() override
{
return m_pOrder;
}
private:
Order* m_pOrder;
};
//具体的建造类
class MeatOrderBuilder : public OrderBuilder
{
public:
MeatOrderBuilder()
{
m_pOrder = new Order;
}
~MeatOrderBuilder()
{
cout << "~MeatOrderBuilder()" << endl;
delete m_pOrder;
m_pOrder = nullptr;
}
void setOrderFood() override
{
m_pOrder->setFood("beef");
}
void setOrderDrink() override
{
m_pOrder->setDrink("beer");
}
Order* getOrder() override
{
return m_pOrder;
}
private:
Order* m_pOrder;
};
//Director类,负责管理实例创建的依赖关系,指挥构建者类创建实例
class Director
{
public:
Director(OrderBuilder* builder) : m_pOrderBuilder(builder)
{
}
void construct()
{
m_pOrderBuilder->setOrderFood();
m_pOrderBuilder->setOrderDrink();
}
private:
OrderBuilder* m_pOrderBuilder;
};
int main()
{
// MeatOrderBuilder* mBuilder = new MeatOrderBuilder;
OrderBuilder* mBuilder = new MeatOrderBuilder; //注意抽象构建类必须有虚析构函数,解析时才会调用子类的析构函数
Director* director = new Director(mBuilder);
director->construct();
Order* order = mBuilder->getOrder();
order->food();
order->drink();
delete director;
director = nullptr;
delete mBuilder;
mBuilder = nullptr;
return 0;
}
9.1 实例2:
建造者模式的定义将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示(DP)。《大话设计模式》举了一个很好的例子——建造小人,一共需建造6个部分,头部、身体、左右手、左右脚。与工厂模式不同,建造者模式是在导向者的控制下一步一步构造产品的。建造小人就是在控制下一步步构造出来的。创建者模式可以能更精细的控制构建过程,从而能更精细的控制所得产品的内部结构。下面给出建造者模式的UML图,以建造小人为实例。
对于客户来说,只需知道导向者就可以了,通过导向者,客户就能构造复杂的对象,而不需要知道具体的构造过程。下面给出小人例子的代码实现。
class Builder
{
public:
virtual void BuildHead() {}
virtual void BuildBody() {}
virtual void BuildLeftArm(){}
virtual void BuildRightArm() {}
virtual void BuildLeftLeg() {}
virtual void BuildRightLeg() {}
};
//构造瘦人
class ThinBuilder : public Builder
{
public:
void BuildHead() { cout<<"build thin body"<<endl; }
void BuildBody() { cout<<"build thin head"<<endl; }
void BuildLeftArm() { cout<<"build thin leftarm"<<endl; }
void BuildRightArm() { cout<<"build thin rightarm"<<endl; }
void BuildLeftLeg() { cout<<"build thin leftleg"<<endl; }
void BuildRightLeg() { cout<<"build thin rightleg"<<endl; }
};
//构造胖人
class FatBuilder : public Builder
{
public:
void BuildHead() { cout<<"build fat body"<<endl; }
void BuildBody() { cout<<"build fat head"<<endl; }
void BuildLeftArm() { cout<<"build fat leftarm"<<endl; }
void BuildRightArm() { cout<<"build fat rightarm"<<endl; }
void BuildLeftLeg() { cout<<"build fat leftleg"<<endl; }
void BuildRightLeg() { cout<<"build fat rightleg"<<endl; }
};
//构造的指挥官
class Director
{
private:
Builder *m_pBuilder;
public:
Director(Builder *builder) { m_pBuilder = builder; }
void Create(){
m_pBuilder->BuildHead();
m_pBuilder->BuildBody();
m_pBuilder->BuildLeftArm();
m_pBuilder->BuildRightArm();
m_pBuilder->BuildLeftLeg();
m_pBuilder->BuildRightLeg();
}
};
// 客户的使用方式:
int main()
{
FatBuilder thin;
Director director(&thin);
director.Create();
return 0;
}
参考资料:https://blog.csdn.net/wuzhekai1985/article/details/6667467