原型模式 详解
定义
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象;
创建型模式
浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值;
深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所有非引用成员变量值,还要为引用类型的成员变量创建新的实例,并且初始化为形式参数实例值;
角色
- 抽象原型类(Prototype):抽象原型类,声明克隆自身的接口;
- 具体原型类(ConcretePrototype):具体原型类,实现克隆的具体操作;
- 客户端(Client):让一个克隆自身,从而获得新的对象;
从网上找到的例图
适用场景
- 当一个系统应该独立于它的产品创建,构成和表示时,要使用Prototype模式;
- 当要实例化的类是在运行时刻指定时,比如动态加载;
- 为了避免创建一个与产品类层次平行的工厂类层次;
- 当一个类的实例只有几个不同状态组合中的一种时,建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些;
例子
实现代码
/**
* Created by George on 16/7/20.
*/
/**
* 第一种创建对象方式
* @type {{name: string, drive: Function, panic: Function}}
*/
var myCar = {
name : "Mini QQ",
drive : function () {
console.log("driving.");
},
panic : function () {
console.log("stop.");
}
};
// 通过Object的create函数实例化一个新的car
var yourCar = Object.create(myCar);
console.log(yourCar.name);
/**
* 第二种创建对象方式
* @type {{getModel: Function}}
*/
var verticle = {
getModel : function () {
console.log("the model of this vehicle is " + this.model);
}
};
// 使用create函数的第二个参数来初始化对象属性
var car = Object.create(verticle, {
"id" : {
value : 1,
enumerable : true
},
"model" : {
value : "QQ",
enumerable : true,
}
});
car.getModel();
// 如果不用上面那种,则
var vehiclePrototype = {
init : function (carModel) {
this.model = carModel;
},
getModel : function () {
console.log("the model of this vehicle is " + this.model);
}
};
function vehicle (model) {
function F () {};
F.prototype = vehiclePrototype;
var f = new F();
f.init(model);
return f;
};
yourCar = new vehicle("QQ");
yourCar.getModel();
/**
* 第三种方式
*/
var beget = (function () {
function F () {};
return function (proto) {
F.prototype = proto;
return new F();
};
})();
yourCar = new beget(vehiclePrototype);
yourCar.init("QQ");
yourCar.getModel();
实现结果:
优缺点
- 原型模式允许在运行时动态改变具体的实现类型;
- 改变值以指定新对象;
- 改变结构以指定新对象;
- 减少子类的构造;
注意的是
- 每个类都必须配备一个克隆方法,比如当所考虑的类已经存在时就难以新增clone操作,当内部包括一些不支持拷贝或有循环引用的对象时,不不容易实现克隆;
![](https://i.loli.net/2018/11/17/5beff4d639cbb.jpg)
关注公众号:数据结构与算法那些事儿,每天一篇数据结构与算法