23种设计模式(C++)之原型(Prototype)模式
23种设计模式(C++)之原型(Prototype)模式
概念
原型(Prototype)模式,是一种对象创建型模式。
意图
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
理解
当需要复制一个类的对象,或者需要创建一个与已有对象的信息基本相同的对象时,通常需要对该对象的所有成员信息进行拷贝,这个过程是很耗费资源的。
原型模式提供一种在类中添加Clone成员函数的方法,通过调用该方法,可快速克隆一个新的对象。
提醒
拷贝包括浅拷贝和深拷贝:
浅拷贝:拷贝者和被拷贝者指向同一内存地址,当一方值发生变化,会影响另一方的值。
深拷贝:因为拷贝时重新分配了资源,因此一方值的变化并不会影响另一方。
在“实例”部分会举例说明这一点,两种拷贝方式都有用途,设计时选择需要的方式即可。
实例
本文以汽车为例,先设计一个含有Clone方法的具体类。
具体类实例
创建汽车具体类
class Car
{
private:
string gearInfo;
string bodyworkInfo;
public:
Car() {}
void setGearInfo(string geartype)
{
this->gearInfo = geartype;
}
string getGearInfo()
{
return this->gearInfo;
}
void setBodyworkInfo(string bodyworktype)
{
this->bodyworkInfo = bodyworktype;
}
string getBodyworkInfo()
{
return this->bodyworkInfo;
}
Car *deepClone()
{
return new Car(*this); //Deep clone
}
Car *shallowClone()
{
Car *car(this); // shallow clone
return car;
}
};
客户端测试
int main()
{
Car *electricCar = new Car();
electricCar->setGearInfo("electric car gear");
electricCar->setBodyworkInfo("white bodywork");
cout << "Electric car gear info: "<<electricCar->getGearInfo()<<"; Electric car bodywork info:"<<electricCar->getBodyworkInfo()<<endl;
// Deep clone
Car *oilCar2 = electricCar->deepClone();
oilCar2->setGearInfo("oil car gear");
cout << "Oil car gear info: " << oilCar2->getGearInfo() << "; Oil car bodywork info: " << oilCar2->getBodyworkInfo() << endl;
cout << "Electric car gear info: " << electricCar->getGearInfo() << "; Electric car bodywork info:" << electricCar->getBodyworkInfo() << endl;
// Shallow copy
Car *oilCar1 = electricCar->shallowClone();
oilCar1->setGearInfo("oil car gear");
cout << "Oil car gear info: " << oilCar1->getGearInfo() << "; Oil car bodywork info: " << oilCar1->getBodyworkInfo() << endl;
cout << "Electric car gear info: " << electricCar->getGearInfo() << "; Electric car bodywork info:" << electricCar->getBodyworkInfo() << endl;
}
Result:
Electric car gear info: electric car gear; Electric car bodywork info:white bodywork
Oil car gear info: oil car gear; Oil car bodywork info: white bodywork
Electric car gear info: electric car gear; Electric car bodywork info:white bodywork
Oil car gear info: oil car gear; Oil car bodywork info: white bodywork
Electric car gear info: oil car gear; Electric car bodywork info:white bodywork
Analysis:
- 对比第一行和第二行结果可以看出:
拷贝的对象oilCar2直接包含了对象electricCar的成员信息。 - 通过第二行和第三行的结果可以看出:
通过深拷贝产生的oilCar2对象,当修改成员信息时,不会影响到electricCar的成员信息。 - 通过第四行和第五行的结果可以看出:
通过浅拷贝产生的oilCar1对象,当修改成员信息时,electricCar的成员信息受到了影响。
抽象类实例
为了便于扩展汽车类型并减少修改原有代码,本例采用抽象类实现原型设计模式。
创建汽车抽象类
class CarPrototype
{
protected:
string gearInfo;
string bodyworkInfo;
public:
virtual void setGearInfo(string geartype) = 0;
virtual string getGearInfo() = 0;
virtual void setBodyworkInfo(string bodyworktype) = 0;
virtual string getBodyworkInfo() = 0;
virtual CarPrototype *carClone() = 0;
};
创建电动汽车类
class ElectricCar : public CarPrototype
{
public:
void setGearInfo(string geartype)
{
this->gearInfo = geartype;
}
string getGearInfo()
{
return this->gearInfo;
}
void setBodyworkInfo(string bodyworktype)
{
this->bodyworkInfo = bodyworktype;
}
string getBodyworkInfo()
{
return this->bodyworkInfo;
}
CarPrototype *carClone()
{
return new ElectricCar(*this); //Deep clone
}
};
客户端测试
int main()
{
CarPrototype *electricCar1 = new ElectricCar();
electricCar1->setGearInfo("electric1");
electricCar1->setBodyworkInfo("white");
cout << "Electric car 1 gear info: " << electricCar1->getGearInfo() << "; Electric1 car 1 bodywork info:" << electricCar1->getBodyworkInfo() << endl;
CarPrototype *electricCar2 = electricCar1->carClone();
electricCar2->setGearInfo("electric2");
cout << "Electric car 2 gear info: " << electricCar2->getGearInfo() << "; Electric car 2 bodywork info: " << electricCar2->getBodyworkInfo() << endl;
}
Result
Electric car 1 gear info: electric1; Electric1 car 1 bodywork info:white
Electric car 2 gear info: electric2; Electric car 2 bodywork info: white
本例默认采用了深拷贝的方式。
如果需要添加新的汽车类型,比如油动汽车,直接添加油动汽车的继承类即可。