<br>
<br>
<br>
##外觀模式
代理模式
<br>
觀察者模式 前言單體模式想法在於保證一個特定類別僅有一個實例,這意味著當你第二次使用同一個類別建立信物件時,應得到和第一次創建物件完全相同。 | 方法一<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> |
工厂模式是为了创建对象。
公共构造函数 CarMaker
名为factory的CarMaker静态方法来创建car对象
<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> |
本例子参考与 大熊君
权限列表
发帖 1
帖子审核 2
删帖 3
留言、回复 4
用户 | 代码 | 权限 |
---|---|---|
注册用户 | 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>通知中介者他所做的事情。中介者将更新后的分数传达给计分板。
除了中介者莫有对象知道其他对象。
<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> |
觀察者模式在 javascript 中使用非常廣泛。所有的瀏覽器時間就是該模式的實現,node.js中的events也是此模式實作。 <br>此模式另一個名稱是 訂閱/發布模式
。 <br>設計這個模式原因是促進形成鬆散耦合,在這種模式中,並不是一個物件調用另一個物件的方法,而是一個物件訂閱另一個物件的<br>特定活動並在狀態改編後獲得通知。訂閱者因此也成為觀察者,而被觀察的對象成為發布者或主題。當發生了一個重要事件時候<br>發布者會通知(呼叫)所有訂閱者並且可能經常已事件物件的形式傳遞訊息。
針對一個類別只建立一個物件。
根據字串制定類型在運行時建立物件的方法。
提供一個API來遍歷或操作複雜的自訂資料結構。
透過從預先定義裝飾者物件中新增功能,從而在運行時侯調整物件
#在懸在最佳策略以處理特定任務的時候仍然保持相同的介面。
透過把常用方法包裝到一個新方法中,從來提供一個更為便利的API。
透過包裝一個物件從而控制對它的訪問,其中主要方法是將方位聚集為租或<br>僅當真正必要時侯才執行訪問,從未避免高昂的操作開銷。
透過是你的物件之間相互不直接“通話”,而是透過一個中介者對子昂進行通信,<br>從而形成鬆散耦合。
透過創建「可觀察」的對象,當發生一個感興趣的事件時可將改時間通告給所有觀察者<br>從而形成鬆散耦合。
以上是關於js設計模式的超詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!