//创建一个Person类
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.toString = function(){
return 'name:'+ this.name + '\tage:' + this.age + '\tsex:' + this.sex;
}
}
//实例化一个Person对象
var person = new Person('niki',24,'男');
console.info(person.toString());
优点
缺点
//申明一个登陆控制器并返回一个对象
var loginController = (function(){
//私有变量
var loginUrl = 'http://localhost/user/login';//登陆地址
var checkUrl = 'http://localhost/user/check';//检查地址
return {
isLogined : false,//是否已登陆
//用户是否存在
checkUser:function(username,password){
if(username === 'admin'){
return true;
}else{
return false;
}
},
//用户登陆
loginUser:function(username,password){
if(username === 'admin' && password === '123456'){
return true;
}else{
return false;
}
}
};
})();
//调用方法
console.info(loginController.checkUser('admin'));
优点
缺点
var user = (function() {
var name;//私有变量
//获取私有变量
function getNameFunc() {
return name;
}
//设置私有变量值
function setNameFunc(value) {
name = value;
}
return {
getName: getNameFunc,
setName: setNameFunc
};
})();
user.setName("niki");
console.info(user.getName());
var mySingleton = (function(){
var instance;//用来存放实例
//实例初始化
function init(){
function privateMethod(){
console.info("I'm private");
}
var privateVariable = "I'm also private";
var privateRandomNumber = Math.random();
return{
publicMethod:function(){
console.info("I'm public");
},
publicVariable:"I'm alse public",
getRandomNumber:function(){
return privateRandomNumber;
}
};
}
return {
//获取实例
getInstance:function(){
if(!instance){
instance = init();
}
return instance;
}
}
})();
var instanceA = mySingleton.getInstance();
var instanceB = mySingleton.getInstance();
var a = instanceA.getRandomNumber();
var b = instanceB.getRandomNumber();
console.info(a + " --- " + b);//a等于b,因为是同一个实例
观察者列表操作类
function ObserverList(){
this.observerList = [];
}
ObserverList.prototype.add = function(obj){
return this.observerList.push(obj);
};
ObserverList.prototype.empty = function(){
this.observerList = [];
};
ObserverList.prototype.count = function(){
return this.observerList.length;
};
ObserverList.prototype.get =function(index){
if(index>-1 && index<this.observerList.length){
return this.observerList[index];
}
};
ObserverList.prototype.insert =function(obj,index){
var pointer = -1;
if(index === 0){
this.observerList.unshift(obj);
pointer = index;
}else if(index === this.observerList.length){
this.observerList.push(obj);
pointer = index;
}
return pointer;
};
ObserverList.prototype.indexOf = function(obj,startIndex){
var i = startIndex,pointer = -1;
while(i < this.observerList.length){
if(this.observerList[i] === obj){
pointer = i;
}
i++;
}
return pointer;
};
ObserverList.prototype.removeIndexAt = function(index){
if(index === 0){
this.observerList.shift();
}else if(index === this.observerList.length - 1){
this.observerList.pop();
}
};
模拟目标类
function Subject(){
this.observers = new ObserverList();
}
Subject.prototype.addObserver = function(observer){
this.observers.add(observer);
};
Subject.prototype.removeObserver = function(observer){
this.observers.removeIndexAt(this.observers.indexOf(observer,0));
};
Subject.prototype.notify = function(context){
var observerCount = this.observers.count();
for(var i=0;i<observerCount;i++){
this.observers.get(i).update(context);
}
};
观察者类
function Observer(){
this.update = function(context){
};
}
案例所需HTML源码
<button id="addNewObserver">Add New Oberver checkbox</button>
<input type="checkbox" name="" id="mainCheckbox"/>
<div id="observerContainer"></div>
实例
var controllerCheckbox = document.getElementById("mainCheckbox"),
addBtn = document.getElementById("addNewObserver"),
container = document.getElementById("observerContainer");
//具体目标
extend(new Subject(),controllerCheckbox);
//点击checkbox会触发到观察者上
controllerCheckbox["onclick"] = new Function("controllerCheckbox.notify(controllerCheckbox.checked)");
addBtn["onclick"] = AddNewObserver;
//具体观察者
function AddNewObserver(){
var check = document.createElement("input");
check.type="checkbox";
extend(new Observer(),check);
check.update = function(value){
this.checked = value;
};
//为主subject的观察者列表添加观察者
controllerCheckbox.addObserver(check);
container.appendChild(check);
}
function extend(obj,extension){
for(var key in obj){
extension[key] = obj[key];
}
}
Publish/Subscribe 的实现
var pubsub = {};
(function(q){
var topics = {},
subUid = -1;
//发布或广播事件
q.publish = function(topic,args){
if(!topics[topic]){
return false;
}
var subscribes = topics[topic],
len = subscribes ? subscribes.length : 0;
while(len--){
subscribes[len].func(topic,args);
}
return false;
};
//通过特定的名称和回调函数订阅事件
q.subscribe = function(topic,func){
if(!topics[topic]){
topics[topic] = [];
}
var token = (++subUid).toString();
topics[topic].push({
token:token,
func:func
});
return token;
};
//基于订阅上的标记引用
q.unsubscribe = function(token){
for(var m in topics){
if(topics[m]){
for(var i=0,j=topics[m].length;i<j;i++){
if(topics[m][i].token === token){
topics[m].splice(i,1);
return token;
}
}
}
}
return this;
};
})(pubsub);
使用案例
var messageLogger = function(topics,data){
console.info("Logging:" + topics + "-" + data);
};
var subscription = pubsub.subscribe("inbox/newMessage",messageLogger);
pubsub.publish("inbox/newMessage","Hello World");
var meidator = (function(){
//存储可被广播或监听的topic
var topics = {};
//订阅一个topic
var subscribe = function(topic,fn){
if(!topics[topic]){
topics[topic] = [];
}
topics[topic].push({context:this,callback:fn});
return this;
};
//发布或广播事件到程序的剩余部分
var publish = function(topic){
var args;
if(!topics[topic]){
return false;
}
args = Array.prototype.slice.call(arguments,1);
for(var i=0,len=topics[topic].length; i<len; i++){
var subscription = topics[topic][i];
subscription.callback.apply(subscription.context,args);
}
return false;
};
return {
publish:publish,
subscribe:subscribe,
installTo:function(obj){
obj.publish = publish;
obj.subscribe = subscribe;
}
};
})();
Object.create方式
Object.create方法有两个参数。参数一必选,代表需要实例化的一个对象;参数二不是必选,当我们提供第二个参数时候,该方法代表了实例化了一个参数二的对象并继承了参数一对象。
var Car = {
name:"Ford Escort",
drive:function(){
console.info("Weeee.I'm driving");
},
panic:function(){
console.info("Wait,How do you stop this thing");
}
};
//var myCar = Object.create(Car);
var myCar = Object.create(Car,{
"speed":{
value:250,
enumerable:true
}
});
console.info(myCar.name);
console.info(myCar.speed);
myCar.drive();
prototype 方式
var vehiclePrototype = {
init:function(model){
this.model = model;
},
getModel:function(){
console.info(this.model);
}
};
function vehicle(model){
function F(){};
F.prototype = vehiclePrototype;
var f = new F();
f.init(model);
return f;
}
var car = vehicle("Ford Escort");
car.getModel();
var CarManage = {
requestInfo :function(model,id){
console.info("requestInfo\tmodel:" + model + "\tid:" + id);
},
buyCar:function(model,id){
console.info("buyCar\tmodel:" + model + "\tid:" + id);
},
arrangeViewing:function(model,id){
console.info("arrangeViewing\tmodel:" + model + "\tid:" + id);
},
execute:function(name){
return CarManage[name] && CarManage[name].apply(CarManage,Array.prototype.slice.call(arguments,1));
}
};
CarManage.execute("requestInfo","Ferrari","100");
CarManage.execute("buyCar","Bens","101");
CarManage.execute("requestInfo","Ford","102");
CarManage.execute("arrangeViewing","BMW","103");
作用
Facade模式是一种结构型模式,为更大的代码体提供一个方便的高层次接口,能够隐藏其底层的真实复杂性。
Facade模式既能简化类的接口,也能将这个类从使用它的代码中解耦出来。这使我们能够直接与子系统交互,这种方式相比直接访问子系统有时不易犯错误。易于使用和实现该模式的时占用空间小。
var module = (function(){
var _private = {
i : 5,
get : function(){
return this.i;
},
set:function(value){
this.i = value;
},
run:function(){
console.info(this.i);
}
};
return {
facade:function(args){
var val = _private.get();
_private.set(val + args.val);
_private.run();
}
};
})();
module.facade({name:"niki",val:10});
//声明水果对象
function Fruit(options){
this.name = options.name || "fruit";
this.color = options.color || "red";
this.price = options.price || 5.00;
this.sell = function(){
console.info("Sell Fruit:" + this.name + "\tcolor:" + this.color + "\tprice:" + this.price);
}
}
//声明一个蔬菜对象
function Vegetable(options){
this.name = options.name || "vegetable";
this.color = options.color || "yellow";
this.price = options.price || 10.50;
this.sell = function(){
console.info("Sell Vegetable:" + this.name + "\tcolor:" + this.color + "\tprice:" + this.price);
}
}
//声明一个超市工厂
function MarketFactory(){
//添加默认货物对象
MarketFactory.prototype.goodsClass = Fruit;
//创建货物对象
MarketFactory.prototype.addGoods = function(options){
if(options.type === "Fruit"){
this.goodsClass = Fruit;
}else{
this.goodsClass = Vegetable;
}
return new this.goodsClass(options);//实例化货物
};
}
//实例化一个超市工厂
var marketFactory = new MarketFactory();
//实例化一个苹果对象
var apple = marketFactory.addGoods({type:"Fruit",name:"apple",color:"red",price:4.98});
apple.sell();
//实例化一个花椰菜对象
var broccoli = marketFactory.addGoods({type:"Vegetable",name:"broccoli",color:"green",price:14.50});
broccoli.sell();
何时使用Factory 模式
何时不应使用Factory 模式
如果应用错误,这种模式会为应用程序带来大量不必要的复杂性。除非创建对象提供一个接口是我们正在编写的库或框架的设计目标,否则建议坚持使用显示构造函数,以避免不必要的开销。
由于对象创建的过程实际上是藏身接口之后抽象出来的,单元测试也可能带来问题,这取决于对象创建的过程有多复杂
Abstract Factory (抽象工厂)
function Fruit(options){
this.name = options.name || "fruit";
this.color = options.color || "red";
this.price = options.price || 5.00;
this.sell = function(){
console.info("Sell Fruit:" + this.name + "\tcolor:" + this.color + "\tprice:" + this.price);
}
}
function Vegetable(options){
this.name = options.name || "vegetable";
this.color = options.color || "yellow";
this.price = options.price || 10.50;
this.sell = function(){
console.info("Sell Vegetable:" + this.name + "\tcolor:" + this.color + "\tprice:" + this.price);
}
}
var AbstractMarketFactory = (function(){
var types = {};
return {
getGoods:function(type,options){
var goods = types[type];
return goods ? new goods(options) : null;
},
registerGoods:function(type,goods){
types[type] = goods;
}
};
})();
AbstractMarketFactory.registerGoods("fruit",Fruit);
AbstractMarketFactory.registerGoods("vegetable",Vegetable);
var apple = AbstractMarketFactory.getGoods("fruit",{type:"Fruit",name:"apple",color:"red",price:4.98});
apple.sell();
var broccoli = AbstractMarketFactory.getGoods("vegetable",{type:"Vegetable",name:"broccoli",color:"green",price:14.50});
broccoli.sell();
子类化
var Person = function(firstName,lastName){
this.firstName = firstName;
this.lastName = lastName;
this.gender = "male";
};
var SuperHero = function(firstName,lastName,powers){
Person.call(this,firstName,lastName);
this.powers = powers;
};
SuperHero.prototype = Object.create(Person.prototype);
var superman = new SuperHero("Clark","Kent",["flight","heat-vision"]);
console.info(superman);
Mixin(混入)
var Car = function(settings) {
this.model = settings.model || "no model provided";
this.color = settings.color || "no color provided";
};
var Mixin = function() {};
Mixin.prototype = {
driveForward: function() {
console.info("drive forward");
},
driveBackward: function() {
console.info("drive backward");
},
driveSideways: function() {
console.info("drive sideways");
}
};
function augment(receivingClass,givingClass){
if(arguments[2]){
for(var i=2,len=arguments.length; i<len;i++){
receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
}
}else{
for(var methodName in givingClass.prototype){
//方式一
if(!Object.hasOwnProperty(receivingClass.prototype,methodName)){
receivingClass.prototype[methodName] = givingClass.prototype[methodName];
}
//方式二
// if(!receivingClass.prototype[methodName]){
// receivingClass.prototype[methodName] = givingClass.prototype[methodName];
// }
}
}
}
augment(Car,Mixin,"driveForward","driveBackward")
var car = new Car({
model:"Ford Escort",
color:"red"
});
car.driveForward();
car.driveBackward();
// car.driveSideways();//因为没有继承,所以会报错
优点和缺点
Mixin有助于减少系统中的重复功能以及增加函数复用。当一个应用程序可能需要在各种对象实例中共享行为时,我们可以通过在Mixin中维持这种共享功能并专注于实现系统中真正不同的功能,来轻松避免任何重复。
当然,Mixin会导致原型污染和函数起源方面的不确定性
function MacBook(){
this.cost = function(){
return 997;
};
this.screenSize = function(){
return 11.6;
};
}
function Memory(macbook){
var v = macbook.cost();
macbook.cost = function(){
return v + 75;
};
}
function Engraving(macbook){
var v = macbook.cost();
macbook.cost = function(){
return v + 200;
};
}
function Insurance(macbook){
var v = macbook.cost();
macbook.cost = function(){
return v + 250;
};
}
var mb = new MacBook();
Memory(mb);
Engraving(mb);
Insurance(mb);
console.info(mb.cost());
console.info(mb.screenSize());