国内的有什么好wordpress主题,seo网站优化是什么,想做网站怎么跟做网站的公司谈判,wordpress如何修改自己的网页文章目录 一、引言二、原型模式三、总结 一、引言
与工厂模式相同#xff0c;原型模式#xff08;Prototype#xff09;也是创建型模式。原型模式通过一个对象#xff08;原型对象#xff09;克隆出多个一模一样的对象。实际上#xff0c;该模式与其说是一种设计模式原型模式Prototype也是创建型模式。原型模式通过一个对象原型对象克隆出多个一模一样的对象。实际上该模式与其说是一种设计模式不如说是一种创建对象的方法对象克隆尤其是创建给定类的对象实例过程很复杂例如要设置许多成员变量的值时使用这种设计模式就比较合适。 二、原型模式
也就是说原型模式是为了使你能够复制已有对象 而又无需使代码依赖它们所属的类。
如果你有一个对象 并希望生成与其完全相同的一个复制品 你该如何实现呢 首先 你必须新建一个属于相同类的对象。 然后 你必须遍历原始对象的所有成员变量 并将成员变量值复制到新对象中。
不错 但有个小问题。 并非所有对象都能通过这种方式进行复制 因为有些对象可能拥有私有成员变量 它们在对象本身以外是不可见的。直接复制还有另外一个问题。 因为你必须知道对象所属的类才能创建复制品 所以代码必须依赖该类。 即使你可以接受额外的依赖性 那还有另外一个问题 有时你只知道对象所实现的接口 而不知道其所属的具体类 比如可向方法的某个参数传入实现了某个接口的任何对象。克隆可能会在父类和子类之间进行并且可能是动态的很明显通过父类的拷贝构造函数无法实现对子类对象的拷贝其实这就是一个多态我们需要给父类提供一个克隆函数并且是一个虚函数。
仍然使用闯关打怪兽的案例来解释。下面是一个怪兽类。我们想让怪物父类拥有clone自己的能力。
// 怪物父类
class Monster {
public:// 构造函数Monster(int life, int magic, int attack): m_life(life), m_magic(magic), m_attack(attack) {}virtual ~Monster() {} // 虚析构函数virtual unique_ptrMonster clone() const 0; //cloneprotected: int m_life; // 生命值int m_magic; // 魔法值int m_attack; // 攻击力
};clone函数意味着调用该成员函数就会从当前类对象复制出一个完全相同的对象通过克隆自已来创建出新对象这当然也是一种创建该类所属对象的方式。这三种怪物实现父类的clone方法。
// 亡灵类
class M_Undead : public Monster {
public:M_Undead(int life, int magic, int attack) : Monster(life, magic, attack) {cout 一只亡灵类怪物来到了这个世界 endl;}unique_ptrMonster clone() const override {cout 亡灵类被克隆了 endl;return make_uniqueM_Undead(*this); // 克隆自身}
};// 元素类
class M_Element : public Monster {
public:M_Element(int life, int magic, int attack) : Monster(life, magic, attack) {cout 一只元素类怪物来到了这个世界 endl;}unique_ptrMonster clone() const override {cout 元素类被克隆了 endl;return make_uniqueM_Element(*this); // 克隆自身}
};// 机械类
class M_Mechanic : public Monster {
public:M_Mechanic(int life, int magic, int attack) : Monster(life, magic, attack) {cout 一只机械类怪物来到了这个世界 endl;}unique_ptrMonster clone() const override {cout 机械类被克隆了 endl;return make_uniqueM_Mechanic(*this); // 克隆自身}
};既然是克隆那么上述M_Undead、M_Element、M_Mechanic中的clone成员函数的实现体是需要修改的。例如某个机械类怪物因为被主角砍了一刀失去了100点生命值导致该怪物对象的m_life成员变量生命值从原来的400变成300那么调用clone方法克隆出来的新机械类怪物对象也应该是300点生命值所以此时M_Mechanic类中clone成员函数中的代码行return new M_Mechanic4000110;就不合适因为这样会创建克隆出一个400点生命值的新怪物不符合clone这个成员函数的本意复制出一个完全相同的对象。
克隆对象自身实际上是需要调用类的拷贝构造函数的。如果程序员在类中没有定义自已的拷贝构造函数那么编译器会在必要的时候但不是一定合成出一个拷贝构造函数。因此**在使用原型模式的时候要注意深拷贝和浅拷贝的问题。**下面添加拷贝构造函数。
// 亡灵类
// 拷贝构造函数
M_Undead::M_Undead(const M_Undead other) : Monster(other) {cout 亡灵类被拷贝了 endl;
}为了方便我们仅写一个。这里我们需要确保能正确编写拷贝构造函数这样调用clone才能正确的克隆出对象。
unique_ptrMonster undead make_uniqueM_Undead(100, 50, 20);
unique_ptrMonster undeadClone undead-clone(); // 克隆亡灵怪物unique_ptrMonster element make_uniqueM_Element(80, 70, 30);
unique_ptrMonster elementClone element-clone(); // 克隆元素怪物unique_ptrMonster mechanic make_uniqueM_Mechanic(120, 40, 50);
unique_ptrMonster mechanicClone mechanic-clone(); // 克隆机械怪物原型模式将克隆过程委派给被克隆的实际对象。 模式为所有支持克隆的对象声明了一个通用接口 该接口能够克隆对象 同时又无需将代码和对象所属类耦合。 通常情况下 这样的接口中仅包含一个 clone方法。 所有的类对 clone方法的实现都非常相似。 该方法会创建一个当前类的对象 然后将原始对象所有的成员变量值复制到新建的类中。 甚至可以复制私有成员变量 因为绝大部分编程语言都允许对象访问其同类对象的私有成员变量。 支持克隆的对象即为原型。 当对象有几十个成员变量和几百种类型时 对其进行克隆甚至可以代替子类的构造。 原型模式就是能够复制已有的对象而又无需使代码依赖它们所属的类。换种说法就是通过已有对象克隆出另一个新的对象并且克隆这个对象不需要使用构造函数。 原型模式的UML图中包含两种角色。
抽象原型类Prototype所有具体原型类的父类在其中声明克隆方法。这里指Monster类。具体原型类oncretePrototype实现在抽象原型类中声明的克隆方法在克隆方法中返回自己的一个克隆对象。这里指M_Undead类、M_Element类和M_Mechanic类。
引入原型模型的定义用原型实例指定创建对象的种类并且通过复制这些原型创建新的对象。简单来说就是通过克隆来创建新的对象实例。 原型模式结构 原型 Prototype 接口将对克隆方法进行声明。 在绝大多数情况下 其中只会有一个名为 clone克隆的方法。具体原型 Concrete Prototype 类将实现克隆方法。 除了将原始对象的数据复制到克隆体中之外 该方法有时还需处理克隆过程中的极端情况 例如克隆关联对象和梳理递归依赖等等。客户端 Client 可以复制实现了原型接口的任何对象。 原型注册表 Prototype Registry 提供了一种访问常用原型的简单方法 其中存储了一系列可供随时复制的预生成对象。 最简单的注册表原型是一个 名称 → 原型的哈希表。 但如果需要使用名称以外的条件进行搜索 你可以创建更加完善的注册表版本。 三、总结
原型模式与工厂方法模式在创建对象时的主要区别在于它们如何处理对象的创建过程和状态复制。
原型模式通过复制现有对象原型来创建新对象新对象的初始状态与原型对象相同这避免了复杂的设置过程。当对象的内部数据复杂且多变时原型模式比工厂方法模式更合适因为它可以直接克隆当前状态无需额外的设置代码。例如在游戏中创建一个具有特定状态的怪物分身使用原型模式可以快速复制这些状态。
工厂方法模式和原型模式在创建对象时都不需要知道具体的类名但它们的工作方式不同。工厂方法模式通过调用创建接口来创建新对象而原型模式通过克隆现有对象。如果对象的创建成本较高或者需要避免复杂的初始化逻辑原型模式是一个更好的选择。总结来说两种模式都能解耦对象的创建过程但原型模式在处理动态和复杂状态的对象时更为高效。
因此如果对象的内部数据比较复杂且多变并且在创建对象的时候希望保持对象的当前状态那么用原型模式显然比原型模式更合适。
工厂方法模式与原型模式在创建对象时的异同点
前面范例中创建怪物对象时这两种模式其实都不需要程序员知道所创建对象所属的类名工厂方法模式是调用相应的创建接口例如使用createMonster接口来创建新的怪物对象该接口中采用代码行new类名参数来完成对象的最终创建工作这仍旧是属于根据类名来生成新对象型模式是调用例如clone程序员可以修改成任意其他名字接口来创建新的怪物对象按照惯例这个接口一般不带任何参数以免破坏克隆接口的统一性。该接口中采用的是代码行new类名(*this)完成对类拷贝构造函数的调用来创建对象所以这种创建对象的方式是根据现有对象来生成新对象
当然也可以把原型模式看成是一种特殊的工厂方法模式工厂方法模式的变体这也是可以的一把原型对象所属的类本身例如M_Undead、M_Element、M_Mechanic看成是创建克隆对象的工厂而工厂方法指的自然就是克隆方法clone。
有时候原型可以作为备忘录模式的一个简化版本 其条件是需要在历史记录中存储的对象的状态比较简单 不需要链接其他外部资源 或者链接可以方便地重建。原型并不基于继承 因此没有继承的缺点。 另一方面 原型需要对被复制对象进行复杂的初始化。 工厂方法基于继承 但是它不需要初始化步骤。
在大量使用组合模式和装饰模式的设计时可以通过原型模式来复制复杂结构 而非从零开始重新构造。