Prototype(原型) — 对象创建型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
注意:该模式主要针对于类对象不是一等对象的语言,如C++。而诸如Python这种,该模式没啥用。
适用场景
- 当一个系统应该独立于它的产品创建,构成和表示时。
- 当要实例化的类是在运行时指定时,例如,通过动态装载。
- 为了避免多次创建与产品类层次平行的工厂类层次时。
- 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
效果
Prototype 有许多与 Abstract Factory 和 Builder 一样的效果:它对客户隐藏了具体的产品类,因此减少了客户知道的名字和数目。此外,这些模式使客户无需改变即可使用与特定应用相关的类。
缺点
Prototype 的主要缺陷是每一个 Prototype 的子类都必须实现 Clone 操作,这可能很困难。
UML 图
示例
class Ball {
public:
Ball(){};
~Ball(){};
virtual Ball* Clone() const {};
virtual void Print(){};
};
class BallA : public Ball {
public:
BallA();
BallA(const BallA& other);
~BallA(){};
virtual Ball* Clone() const;
virtual void Print();
private:
string _ball_type;
};
BallA::BallA() {
_ball_type = "ball number one";
}
BallA::BallA(const BallA& other) {
_ball_type = other._ball_type;
}
Ball* BallA::Clone() const {
return new BallA(*this);
}
void BallA::Print() {
cout << _ball_type << endl;
}
class BallB : public Ball {
public:
BallB();
~BallB(){};
BallB(const BallB&);
virtual Ball* Clone() const;
virtual void Print();
private:
string _ball_type;
};
BallB::BallB() {
_ball_type = "ball number two";
}
BallB::BallB(const BallB& other) {
_ball_type = other._ball_type;
}
Ball* BallB::Clone() const {
return new BallB(*this);
}
void BallB::Print() {
cout << _ball_type << endl;
}
class Gun {
public:
Gun();
bool FillBall();
void UpdateBall(Ball* ball);
void Shot();
private:
Ball* ball[100];
int now_ball_num;
Ball* now_ball;
};
Gun::Gun() {
now_ball_num = 0;
}
bool Gun::FillBall() {
if (now_ball_num >= 100 || now_ball == NULL) {
return false;
}
ball[now_ball_num++] = now_ball->Clone();
return true;
}
void Gun::UpdateBall(Ball* ball) {
now_ball = ball;
}
void Gun::Shot() {
// cout << now_ball_num << endl;
for (int i = 0; i < now_ball_num; i++) {
ball[i]->Print();
}
}
client
int main() {
Gun my_gun = Gun();
BallA ball1 = BallA();
my_gun.UpdateBall(&ball1);
my_gun.FillBall();
my_gun.FillBall();
my_gun.FillBall();
BallB ball2 = BallB();
my_gun.UpdateBall(&ball2);
my_gun.FillBall();
my_gun.FillBall();
my_gun.Shot();
}
/**
* output:
* ball number one
* ball number one
* ball number one
* ball number two
* ball number two
* /