|
<br>
缺点
instance 属性暴露。
方法二
使用闭包
<br> |
function Universe(){
var instance=this; //缓存this
this.xx="xx";
Universe=function(){ //重写此构造函数
return instance;
}
}
var uni=new Universe();
var uni2=new Universe();
uni===uni2; //true <br>
|
缺点
因为重写了构造函数,constructor 还是指向了老的构造函数,且实例化后在添加原型属性也是不一样的。如下
<br> |
var uni = new Universe();
Universe.prototype.a = 1
var uni2 = new Universe();
console.log(uni === uni2) //true
console.log(uni.a) //undefinded
console.log(uni2.a) //undefinded
console.log(uni.constructor === Universe); //false <br>
|
方法三
解决方法二问题。
<br>
<br>
|
function Universe(){
var instance;
Universe=function Universe(){
return instance ;
}
Universe.prototype=this; //保存原型属性
instance=new Universe();
instance.constructor=Universe;
instance.xx="xx";
} <br>
|
方法四
自运行函数。
<br> |
var Universe;
(function(){
var instance;
Universe=function Universe(){
if(instance){
return instance;
}
instance=this;
this.xx="xx";
}
})();
var uni = new Universe();
Universe.prototype.a = 1
var uni2 = new Universe();
console.log(uni === uni2) //true
console.log(uni.a) //1
console.log(uni2.a) //1
console.log(uni.constructor === Universe); //true <br>
|
工厂模式
工厂模式是为了创建对象。
例子
<br> |
var corolla=CarMaker.factory('compact');
var solstice=CarMaker.factory('convertible');
var cherokee=CarMaker.factory('suv');
corolla.drive() //I have 4 doors
solstice.drive() //I have 2 doors
cherokee.drive() //I have 6 doors <br>
|
实现
<br>
<br>
|
<br> function CarMaker() {}
CarMaker.prototype.drive = function() {
return "I have " + this.doors + " doors";
}
CarMaker.compact = function() {
this.doors = 4;
}
CarMaker.convertible = function() {
this.doors = 2
}
CarMaker.suv = function() {
this.doors = 6;
}
CarMaker.factory = function(type) {
if (typeof CarMaker[type] !== "function") {
throw "Error"
}
if (typeof CarMaker[type].prototype.drive !== "function") {
CarMaker[type].prototype = new CarMaker();
}
var newCar = new CarMaker[type]();
return newCar;
}
var corolla = CarMaker.factory('compact');
console.log(corolla.drive()); //I have 4 doors <br>
|
内置工厂对象
Object() 构造函数即为内置工厂对象。
迭代器模式
有一个包含某种数据集合的对象,该数据可能存储在一个复杂数据结构内部,而要提供一个简单方法讷讷感访问到数据结构中没一个元素。
next() 下一个
hasNext() 是否有下一个
reWind() 重置指针
current() 返回当前
<br>
<br>
|
var agg = (function() {
var index = 0;
var data = [1, 2, 3, 4, 5, 6];
var length = data.length;
return {
next: function() { //这里是从第一个数据开始输出 本例中为 1
if (!this.hasNext()) {
return null;
}
var element = data[index];
index++;
return element;
},
hasNext: function() {
return index < length;
},
reWind: function() {
index = 0;
},
current: function() {
return data[index];
}
}
})();
while (agg.hasNext()) {
console.log(agg.next()); //1,2,3,4,5,6
}
agg.reWind(); //此时重置指针到0 <br>
|
装饰者模式
可以在运行时候添加附加功能到对象中,他的一个方便特征在于其预期行为的可定制和可配置特性。
例子 假设在开发一个销售商品的Web应用,每一笔信销售都是一个人新的 sale 对象。该对象“知道”有关项目的价格,并可以通过 getPrice() 方法返回加个。<br>根据不同情况,可以用额外的功能装饰此对象。<br>假设客户在魁北克省,买房需要支付联邦税和魁北克省税,则此时需要调用联邦税装饰者和魁北克省税装饰者。
<br> |
var sale=new Sale(100);
sale=sale.decorate("fedtax"); //联邦税
sale=sale.decorate("quebec"); //魁北克省税
sale=sale.decorate("miney"); //转为美元格式
sale.getPrice(); //返回价格 <br>
|
并且装饰是可选的,例如不再魁北克省有可能没有省税。
方法一
<br> |
function Sale(price) {
this.price = price;
}
Sale.prototype.getPrice = function() {
return this.price;
};
Sale.decorators = {}; //储存装饰者的对象
//装饰者
Sale.decorators.fedtax = {
getPrice: function() {
var price = this.uber.getPrice();
return price * 0.8; //对price进行处理
},
}
Sale.decorators.quebec = {
getPrice: function() {
var price = this.uber.getPrice();
return price * 0.7; //对price进行处理
},
}
Sale.decorators.money = {
getPrice: function() {
var price = this.uber.getPrice();
return "$" + price * 0.9; //对price进行处理
},
}
/*decorate() 方法
调用装饰者方法 sale.=sale.decorate("fedtax");
fedtax字符串对应 Sale.decorators中的对象属性。新装饰对象 newobj 将继承目前我们所拥有的对象,这就是ixiangthis
为了完成继承部分代码,此时需要一个临时构造函数,先设置 newobj 的 uber 属性,以便于自对象可以访问到父对象。之后从装饰者中
将所有的额外属性复制到新装饰的对象 newobj 中,最后返回 newobj。
*/
Sale.prototype.decorate = function(decorate) {
var F = function() {};
var overrides = this.constructor.decorators[decorate]; //获取装饰者对象
F.prototype = this;
var newobj = new F();
newobj.uber = F.prototype;
for (var key in overrides) {
if (overrides.hasOwnProperty) { //判断对象是不是自身的
newobj[key] = overrides[key];
}
}
return newobj;
};
var sale = new Sale(100);
sale = sale.decorate("fedtax"); //联邦税
sale = sale.decorate("quebec"); //魁北克省税
sale = sale.decorate("money"); //转为美元格式
console.log(sale.getPrice()); //$50.4 <br>
|
方法二
此方法使用列表实现,而且相对来说比较好理解一点。本质就是把装饰者名称保存到一个列表中并且一次调用此列表中的方法。
<br>
<br>
|
function Sale(price) {
this.price = price;
this.decorateList = [];
}
Sale.decorators = {};
Sale.decorators.fedtax = {
getPrice: function(price) {
var price = this.uber.getPrice();
return price * 0.8; //对price进行处理
},
}
Sale.decorators.quebec = {
getPrice: function(price) {
var price = this.uber.getPrice();
return price * 0.7; //对price进行处理
},
}
Sale.decorators.money = {
getPrice: function(price) {
var price = this.uber.getPrice();
return "$" + price * 0.9; //对price进行处理
},
}
Sale.prototype.decorate = function(decorator) {
this.decorateList.push(decorator);
};
Sale.prototype.getPrice = function() {
var price = this.price;
this.decorateList.forEach(function(name) {
price = Sale.decorators[name].getPrice(price);
});
return price;
};
var sale = new Sale(100);
sale = sale.decorate("fedtax"); //联邦税
sale = sale.decorate("quebec"); //魁北克省税
sale = sale.decorate("money"); //转为美元格式
console.log(sale.getPrice()); //$50.4 <br>
|
策略模式
策略模式支持在运行时候选择算法。例如用在表单验证问题上,可以创建一个具有 validate() 方法的验证器对象,无论表单具体类型是什么,该方法都会被调用,<br>并且返回结果或者错误信息。
<br>
<br>
|
var validator = {
// 所有可以的验证规则处理类存放的地方,后面会单独定义
types: {},
// 验证类型所对应的错误消息
messages: [],
// 当然需要使用的验证类型
config: {},
// 暴露的公开验证方法
// 传入的参数是 key => value对
validate: function (data) {
var i, msg, type, checker, result_ok;
// 清空所有的错误信息
this.messages = [];
for (i in data) {
if (data.hasOwnProperty(i)) {
type = this.config[i]; // 根据key查询是否有存在的验证规则
checker = this.types[type]; // 获取验证规则的验证类
if (!type) {
continue; // 如果验证规则不存在,则不处理
}
if (!checker) { // 如果验证规则类不存在,抛出异常
throw {
name: "ValidationError",
message: "No handler to validate type " + type
};
}
result_ok = checker.validate(data[i]); // 使用查到到的单个验证类进行验证
if (!result_ok) {
msg = "Invalid value for *" + i + "*, " + checker.instructions;
this.messages.push(msg);
}
}
}
return this.hasErrors();
},
// helper
hasErrors: function () {
return this.messages.length !== 0;
}
};
//然后剩下的工作,就是定义types里存放的各种验证类了
// 验证给定的值是否不为空
validator.types.isNonEmpty = {
validate: function (value) {
return value !== "";
},
instructions: "传入的值不能为空"
};
// 验证给定的值是否是数字
validator.types.isNumber = {
validate: function (value) {
return !isNaN(value);
},
instructions: "传入的值只能是合法的数字,例如:1, 3.14 or 2010"
};
// 验证给定的值是否只是字母或数字
validator.types.isAlphaNum = {
validate: function (value) {
return !/[^a-z0-9]/i.test(value);
},
instructions: "传入的值只能保护字母和数字,不能包含特殊字符"
};
//使用的时候,我们首先要定义需要验证的数据集合,然后还需要定义每种数据需要验证的规则类型,代码如下:
var data = {
first_name: "Tom",
last_name: "Xu",
age: "unknown",
username: "TomXu"
};
validator.config = {
first_name: 'isNonEmpty',
age: 'isNumber',
username: 'isAlphaNum'
};
//最后获取验证结果
validator.validate(data);
if (validator.hasErrors()) {
console.log(validator.messages.join("\n"));
} <br>
|
策略模式定义及例子实现参考与《javascript模式》及 汤姆大叔的博客
外观模式
外观模式即让多个方法一起被调用
例如。 stopPropagation() 和 preventDefault() 兼容性一起调用。
<br>
<br>
|
var myEvent = {
stop: function(e) {
if (typeof e.preventDefault() === "function") {
e.preventDefault();
}
if (typeof e.stopPropagation() === "function") {
e.stopPropagation();
}
//for IE
if (typeof e.returnValue === "boolean") {
e.returnValue = false;
}
if (typeof e.cancelBubble === "boolean") {
e.cancelBubble = true;
}
}
} <br>
|
代理模式
在代理模式中,一个对象充当另外一个对象的接口,和外观模式区别是:外观模式是合并调用多个方法。<br>代理模式是介于对象的客户端和对象本身之间,并且对该对象的访问进行保护。
包裹例子
现在有个包裹,卖家要把这个包裹寄给gary,则需要通过快递公司寄过来,此时快递公司就是一个 proxy
<br>
<br>
|
var package = function(receiver) {
this.receiver = receiver;
}
var seller = function(package) {
this.package = package;
this.send = function(gift) {
return package.receiver + "你的包裹:" + gift;
}
}
var express = function(package) {
this.package = package;
this.send = function(packageName) {
return new seller(package).send(packageName);
}
}
//调用
var ems = new express(new package("gary"));
console.log(ems.send("键盘")); //gary你的包裹:键盘 <br>
|
论坛权限管理例子
本例子参考与 大熊君
用户 |
代码 |
权限 |
注册用户 |
001 |
1 4 |
论坛管理员 |
002 |
2 3 4 |
系统管理员 |
003 |
1 2 3 4 |
游客 |
000 |
null |
用户类
<br>
<br>
|
function User(name, code) {
this.name = name;
this.code = code;
}
User.prototype.getName = function() {
return this.name;
};
User.prototype.getCode = function() {
return this.code;
};
User.prototype.post = function() {
//发帖功能
};
User.prototype.remove = function() {
// 删帖功能
};
User.prototype.check = function() {
//审核
};
User.prototype.comment = function() {
//留言回复
}; <br>
|
论坛类
<br>
<br>
|
function Forum(user) {
this.user=user;
}
Forum.prototype.getUser = function () {
return this.user;
};
Forum.prototype.post = function () {
var code=this.user.getCode();
if(code=="001"||code=="003"){
return this.user.post();
}else{
return false;
}
};
Forum.prototype.remove = function () {
var code=this.user.getCode();
if(code=="002"||code=="003"){
return this.user.remove();
}else{
return false;
}
};
Forum.prototype.check = function () {
var code=this.user.getCode();
if(code=="002"||code=="003"){
return this.user.check();
}else{
return false;
}
};
Forum.prototype.comment = function () {
var code=this.user.getCode();
if(code=="001"||code=="002"||code=="003"){
return this.user.comment();
}else{
return false;
}
}; <br>
|
运行
<br>
<br>
|
new Forum(new User("administartor","003")); <br>
|
中介者模式
中介者模式可以让多个对象之间松耦合,并降低维护成本
例如:游戏程序,两名玩家分别给与半分钟时间来竞争决出胜负(谁按键的次数多胜出,这里玩家1按1,玩家2按0)
计分板(scoreboard)
中介者 (mediator)
中介者知道所有其他对象的信息。他与输入设备(此时是键盘)进行通信并处理键盘上的按键时间,之后还将消息通知玩家。玩家玩游戏同时(每一分都更新自己分数)还要<br>通知中介者他所做的事情。中介者将更新后的分数传达给计分板。
除了中介者莫有对象知道其他对象。
JS 디자인 패턴에 대한 매우 상세한 소개
<br>
<br>
|
function Player(name) {
this.points = 0;
this.name = name;
}
Player.prototype.play = function() {
this.points += 1;
mediator.played();
};
var scoreboard = {
element: "这里是获取的element用于展示分数",
update: function(score) { //更新分数
var msg;
for (var key in score) {
if (score.hasOwnProperty(key)) {
msg += score[key];
}
}
this.element.innerText = msg;
},
}
var mediator = {
players: {}, //玩家对象
setup: function() {
var players = this.players;
players.home = new Player("home");
players.guest = new Player('guest');
},
played: function() {
var players = this.players;
var score = {
home: players.home.points,
guest: players.guest.points
}
},
keypress: function(e) {
e = e || window.event;
if (e.which === 49) { //or keycode 对应按键 1
mediator.players.home.play();
return;
}
if (e.which === 48) { // 对应按键 0
mediator.player.guest.play();
return;
}
},
}
//运行
mediator.setup();
window.onkeypress = mediator.keypress;
setTimeout(function() { //设置30秒游戏时间
window.onkeypress = null;
alert("game end");
}, 30000); <br>
|
Observer Pattern
Observer 패턴은 자바스크립트에서 매우 널리 사용됩니다. 모든 브라우저 시간은 이 모드의 구현이며 node.js의 이벤트도 이 모드의 구현입니다. <br>이 모드의 또 다른 이름은 订阅/发布模式 입니다. <br>이 패턴을 설계한 이유는 느슨한 결합을 촉진하기 위한 것입니다. 이 패턴에서는 한 개체가 다른 개체의 메서드를 호출하는 대신 한 개체가 다른 개체의 <br>특정 활동을 구독하고 상태가 적용된 후 알림을 받습니다. 따라서 구독자는 관찰자가 되고, 관찰된 개체는 게시자 또는 주제가 됩니다. 중요한 이벤트가 발생하면 게시자는 모든 구독자에게 알리(전화)하고 이벤트 객체 형태로 메시지를 전달하는 경우가 많습니다. <br> 요약1. 싱글톤 모드클래스당 하나의 개체만 만듭니다. 2. 팩토리 패턴 문자열을 기반으로 지정된 유형을 기반으로 런타임에 객체를 생성하는 방법입니다. 3. 반복자 패턴 복잡한 사용자 정의 데이터 구조를 탐색하거나 작동하는 API를 제공합니다. 4. 데코레이터 패턴 미리 정의된 데코레이터 개체의 기능을 추가하여 런타임에 개체를 조정합니다. 5. 전략 패턴 특정 작업 인터페이스를 처리하기 위한 최상의 전략을 고수하는 동안에도 마찬가지입니다. 6. 모양 모드 일반적인 메소드를 새로운 메소드로 패키징하여 더욱 편리한 API를 제공합니다. 7. 프록시 패턴 은 개체를 래핑하여 개체에 대한 액세스를 제어합니다. 주요 방법은 위치를 임대료로 집계하거나 실제로 필요한 경우에만 액세스를 수행하고 높은 작업 오버헤드를 피하지 않는 것입니다. <br> 8. 터미네이터 패턴객체가 서로 직접 "대화"하는 것이 아니라 중개자를 통해 서로 통신하여느슨한 결합을 형성합니다. <br> 9. 관찰자 패턴관측 가능한 객체를 생성하여 관심 있는 이벤트가 발생하면 모든 관찰자에게 시간을 통보할 수 있어 느슨한 결합을 형성할 수 있습니다.
|