设计模式学习–原型模式
文章理论部分参考以下链接
一、原型模式介绍
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。它实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。原型模式属于创建型模式。
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
主要解决:在运行期建立和删除原型。
何时使用: 1、当一个系统应该独立于它的产品创建,构成和表示时。 2、当要实例化的类是在运行时刻指定时,例如,通过动态装载。 3、为了避免创建一个与产品类层次平行的工厂类层次时。 4、当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。
关键代码: 1、实现克隆操作,在 JAVA 继承 Cloneable,重写 clone(),在 .NET 中可以使用 Object 类的 MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。 2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些”易变类”拥有稳定的接口。
应用实例: 1、细胞分裂。 2、JAVA 中的 Object clone() 方法。
优点: 1、性能提高。 2、逃避构造函数的约束。
缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、逃避构造函数的约束。
使用场景:
1、资源优化场景。
2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
3、性能和安全要求的场景。
4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
5、一个对象多个修改者的场景。
6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。
注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。
抽象基类:
l)Prototype:虚拟基类,所有原型的基类,提供Clone接口函数
接口函数:
1) Prototype::Clone函数:纯虚函数,根据不同的派生类来实例化创建对象.
解析:
原型模式其实就是常说的”虚拟构造函数”一个实现,C++的实现机制中并没有支持这个特性,但是通过不同派生类实现的Clone接口函数可以完成与”虚拟构造函数”同样的效果。举一个例子来解释这个模式的作用,假设有一家店铺是配钥匙的,他对外提供配制钥匙的服务(提供Clone接口函数),你需要配什么钥匙它不知道只是提供这种服务,具体需要配什么钥匙只有到了真正看到钥匙的原型才能配好.也就是说,需要一个提供这个服务的对象,同时还需要一个原型(Prototype),不然不知道该配什么样的钥匙.
二、实现演练
首先,给出对UML结构图对应的解释代码。
//虚拟基类,所有原型的基类,提供Clone接口函数
class Prototype
{
public:
Prototype(){}
virtual ~Prototype(){}
virtual Prototype* Clone()=0;
};
//派生自Prototype,实现Clone方法
class ConcretePrototype1:public Prototype
{
public:
ConcretePrototype1()
{
cout<<"ConcretePrototype1"<<endl;
}
ConcretePrototype1(const ConcretePrototype1& p)
{
cout<<"ConcretePrototype1 copy..."<<endl;
}
virtual ~ConcretePrototype1(){}
virtual Prototype* Clone()
{
return new ConcretePrototype1(*this);
}
};
//派生自Prototype,实现Clone方法
class ConcretePrototype2:public Prototype
{
public:
ConcretePrototype2()
{
cout<<"ConcretePrototype2"<<endl;
}
ConcretePrototype2(const ConcretePrototype2& p)
{
cout<<"ConcretePrototype2 copy..."<<endl;
}
virtual ~ConcretePrototype2(){}
virtual Prototype* Clone()
{
return new ConcretePrototype2(*this);
}
};
int main()
{
Prototype* p1 = new ConcretePrototype1();
Prototype* p2 = p1->Clone();
Prototype* p3 = new ConcretePrototype2();
Prototype* p4 = p3->Clone();
delete p1;
delete p2;
delete p3;
delete p4;
return 0;
}
再来,给出一个网上看到的例子。
(1)创建一个虚拟基类,所有原型的基类,提供Clone接口函数。
// 克隆接口
template<class T>
class ICloneable
{
public:
virtual T* clone() = 0;
};
(2)创建一个工作经历类,它用来丰富原型类的内容。
class CWorkExperience
{
public:
CWorkExperience(){}
CWorkExperience(const string& company,
const string& workTime)
{
m_strCompany = company;
m_strWorkTime = workTime;
}
CWorkExperience(const CWorkExperience& right)
{
m_strCompany = right.m_strCompany;
m_strWorkTime = right.m_strWorkTime;
}
~CWorkExperience()
{
cout << "CWorkExperience析构" << endl;
printInfo();
}
void setCompany(const string& company)
{
m_strCompany = company;
}
const string& getCompany() const
{
return m_strCompany;
}
void setWorkTime(const string& workTime)
{
m_strWorkTime = workTime;
}
const string& getWorkTime() const
{
return m_strWorkTime;
}
void printInfo()
{
cout << "Company: " << m_strCompany << endl;
cout << "WorkTime: " << m_strWorkTime << endl;
}
private:
string m_strCompany; // company name
string m_strWorkTime; // work time
};
(3)派生自Prototype基类,实现Clone方法
// 简历类
class CResume : public ICloneable<CResume>
{
public:
CResume(){}
~CResume()
{
cout << "CResume析构 " << m_name << endl;
}
void setInfo(const string& name, const string& sex
, int age)
{
m_name = name;
m_sex = sex;
m_age = age;
}
void setExperience(const string& company, const string& workTime)
{
m_experience.setCompany(company);
m_experience.setWorkTime(workTime);
}
CResume* clone()
{
CResume* resume = new CResume;
resume->setInfo(m_name, m_sex, m_age);
resume->setExperience(m_experience.getCompany(), m_experience.getWorkTime());
return resume;
}
/*浅拷贝的实现
CResume(const CResume& right)
{
m_name = right.m_name;
m_sex = right.m_sex;
m_age = right.m_age;
// 注意这里是指针赋值 属于浅拷贝
m_experience = right.m_experience;
} */
void printInfo()
{
cout << "Name: " << m_name << endl;
cout << "Sex: " << m_sex << endl;
cout << "Age: " << m_age << endl;
cout << "Experience: " << endl;
m_experience.printInfo();
cout << endl;
}
protected:
string m_name;
string m_sex;
int m_age;
CWorkExperience m_experience;// 对象
};
(4)测试功能的函数
void testPrototype()
{
CResume re;
re.setInfo("Jacky", "Male", 20);
re.setExperience("MS", "2001.11 - 2005.11");
re.printInfo();
CResume* pClone = re.clone();
pClone->setInfo("Marry", "Female", 30);
pClone->setExperience("Google", "2006.01 - 2010.01");
pClone->printInfo();
delete pClone;
pClone = NULL;
}
int main(void)
{
testPrototype();
return 0;
}