设计模式提供了一些可重用的解决方案, 这些方案适用于便携 javaScript Web 应用.
参考学习 Deven dalao 的文章作为学习笔记.
原文地址
参考文章
1.Constructor Pattern. (构造方法模式)
这种特殊的方法,被用于内存在内存初始化之后分配一个新创建的对象,javaScript 是面相对象的, 所以我们研究最多的就是 对象构造器(object Constructor)
// 这里有 3 中方式去创建一个 javaScript 对象
var newObject_0 = {};
// OR
var newObject_1 = Object.create(Object.prototype);
// OR
var newObject_2 = new Object();
// 有以下几种方式可以将属性放入一个对象
// 1. .
// 设置属性
newObject_0.hello = "hello newObject_0";
// 2. 方括号
newObject_0['square_hello'] = "hello newObject_0";
// 3.Object.defineProperty 兼容性参考 http://kangax.github.io/compat-table/es5/
Object.defineProperty(newObject_1, "someKey", {
value: "for more control of the property's behavior",
writable: true,
enumerable: true,
configurable: true
});
// 我们可以写个方法
const defindProp = (obj, key, value) => {
var config = {
value: value,
writable: true,
enumerable: true,
configurable: true
};
Object.defineProperty(obj, key, config)
}
const myObj = Object.create(Object.prototype);
defindProp(myObj, 'eat', '什么都吃');
defindProp(myObj, 'money', '0');
// 4. Object.defineProperties
Object.defineProperties(newObject_2, {
"key1": {
value: "Hello World",
writable: true
},
"key2": {
value: "Foo bar",
writable: false
}
});
console.log(newObject_2);
// 如果需要访问函数的属性, 你需要去初始化对象
// const object = new constructorObject();
// 据此 new 关键词在这里告诉 javaScript constructorObject 应当充当一个构造器,另外这个方法并不支持继承
// 基础构造器
function Computer(cpu, os) {
this.cpu = cpu;
this.os = os;
this.toString = () => this.cpu + '系统是:' + this.os}
const WinPc = new Computer('i7', 'windows');
const LinuxPc = new Computer('i5', 'Linux');
console.log({WinPc: WinPc.toString(),
LinuxPc: LinuxPc.toString()})
2. Prototype Pattern 原型模式
原型模式主要基于原型继承,被创建的对象充当其他对象的原型,实际上原型(prototypes act)作为每个对象构造器的蓝图
var myCar = {
name: "Ford Escort",
drive: function () {console.log("Weeee. I'm driving!");
},
panic: function () {console.log("Wait. How do you stop this thing?");
}
};
// Use Object.create to instantiate a new car
var yourCar = Object.create(myCar);
// Now we can see that one is a prototype of the other
console.log(yourCar.name);
3.Module Pattern 模块设计模式
在模块(Module)设计模式下, 对原型(Prototype)模式进行了一些改进,没模块模式使用两种不同的修饰符(private 和 public),你可以创建互不冲突的相似函数属性,你可以灵活的重命名共有函数(functions publicly)。这个模式的缺陷是不能 覆盖(override)外部环境中创建的函数
var myModule = {
myProperty: "someValue",
// object literals can contain properties and methods.
// e.g we can define a further object for module configuration:
myConfig: {
useCaching: true,
language: "cn"
},
// 说点什么
saySomething: function () {console.log("吃了么?");
},
// 输出当前状态
reportMyConfig: function () {console.log("Caching is:" + (this.myConfig.useCaching ? "enabled" : "disabled"));
},
// override the current configuration
updateMyConfig: function (newConfig) {if (typeof newConfig === "object") {
this.myConfig = newConfig;
console.log(this.myConfig.language);
}
}
};
myModule.saySomething();
myModule.reportMyConfig();
myModule.updateMyConfig({
language: "en",
useCaching: false
});
myModule.reportMyConfig();
4. Singleton Pattern 单例模式
在仅需要创建一个实例的情况下(如一个数据库连接),这个模式就是必须的。在这个模式种,只有在关闭连接或者确定打开新实例钱必须关闭已有实例时可以创建一个新实例。这个模式也成为严格模式(strict pattern),他的一个缺陷是在测试时的体验糟糕,因为他很难单独拿出来进行测试
function DatabaseConnection() {
let databaseInstance = null;
// tracks the number of instances created at a certain time
let count = 0;
function init() {console.log(`Opening database #${count + 1}`);
//now perform operation
}
function createIntance() {if (databaseInstance == null) {databaseInstance = init();
}
return databaseInstance;
}
function closeIntance() {console.log('closing database');
databaseInstance = null;
}
return {
open: createIntance,
close: closeIntance
}
}
const database = DatabaseConnection();
database.open(); //Open database #1
database.open(); //Open database #1
database.open(); //Open database #1
database.close(); //close database
5. Factory Pattern 工厂模式
工厂模式的创新之处在于他不需要 构造器(constructor)就能创建对象. 他提供了一个通用接口去创建兑现,你可以指定想要的工厂对象(actory objects)类型。这样一来,我们只需要指定对象然后 工厂实例化并返回对象给我们使用。当对象组件设置起来很复杂,并希望根据不同的环境创建不同的对象实例时候, 建议使用工厂模式。在处理多共享相同属性的小型对象, 以及创建一些需要解耦(decoupling)的组合对象的时候,也可以使用工厂模式
// Dealer A
DealerA = {};
DealerA.title = function title() {return "Dealer A";};
DealerA.pay = function pay(amount) {
console.log(`set up configuration using username: ${this.username} and password: ${this.password}`
);
return `Payment for service ${amount} is successful using ${this.title()}`;
};
//Dealer B
DealerB = {};
DealerB.title = function title() {return "Dealer B";};
DealerB.pay = function pay(amount) {
console.log(`set up configuration using username: ${this.username}
and password: ${this.password}`
);
return `Payment for service ${amount} is successful using ${this.title()}`;
};
//@param {*} dealerOption
//@param {*} config
function DealerFactory(dealerOption, config = {}) {const dealer = Object.create(dealerOption);
Object.assign(dealer, config);
return dealer;
}
const dealerFactory = DealerFactory(DealerA, {
username: "user",
password: "pass"
});
console.log(dealerFactory.title());
console.log(dealerFactory.pay(12));
const dealerFactory2 = DealerFactory(DealerB, {
username: "user2",
password: "pass2"
});
console.log(dealerFactory2.title());
console.log(dealerFactory2.pay(50));
6. Observer Pattern 观察者模式
观察者(Observer)模式在多对象同时(simultaneously)与其他对象通信(communicate)的场景中使用很方便。在观察者模式下,没有非必须的 push 和 pull,相比之下, 所涉及的模块仅会修改数据的当前状态
function Observer() {this.observerContainer = [];
}
Observer.prototype.subscribe = function (element) {this.observerContainer.push(element);
}
// the following removes an element from the container
Observer.prototype.unsubscribe = function (element) {const elementIndex = this.observerContainer.indexOf(element);
if (elementIndex > -1) {this.observerContainer.splice(elementIndex, 1);
}
}
/**
* we notify elements added to the container by calling
* each subscribed components added to our container
*/
Observer.prototype.notifyAll = function (element) {this.observerContainer.forEach(function (observerElement) {observerElement(element);
});
};
7. Command Pattern 命令模式
命令(Command)模式讲方法的调用,操作和请求封装到单个对象中,一边可以自行传递方法调用。命令模式可以从任何正在执行的命令中发出命令,并将责任委托给之前不同的对象, 这些命令以 run() 和 execute() 格式显示
(function () {
var carManager = {
//information requested
requestInfo: function (model, id) {return "The information for" + model + "with ID" + id + "is foo bar";},
// now purchase the car
buyVehicle: function (model, id) {return "You have successfully purchased Item" + id + ", a" + model;},
// now arrange a viewing
arrangeViewing: function (model, id) {return "You have successfully booked a viewing of" + model + "(" + id + ")";
}
};
carManager.execute = function (name) {return carManager[name] && carManager[name].apply(carManager, [].slice.call(arguments, 1));
};
let carExec = carManager.execute("buyVehicle", "Ford Escort", "453543");
// console.log(carExec)
})();