设计模式
它不是一个类库
它不是一个框架
它也不是一段代码
它是解决问题的一种思路和方法
1.单例模式
定义:保证一个类仅有一个实例
本质:控制实例数目
单例模式思想在于保证一个特定类仅有一个实例,意味着当你第二次使用同一个类创建信对象时应得到和第一次创建对象完全相同。
//外面包一层自运行函数
var Popup = (function(){
//创建div元素只执行了一次
var div = document.createElement("div");
document.body.appendChild(div);
//唯一的对象
var instance = null;
//真正得到的函数
return function(){
if(instance == null){
instance = new Object();
instance.show = function(){
div.style.display = "block";
}
instance.hide = function(){
div.style.display = "none";
}
}
//每次实例化返回相同的对象
return instance;
}
})();
2.代理模式
定义:为其他对象提供一种代理以控制对这个对象的访问
本质:控制对象访问
代理(proxy)是一个对象,它可以用来控制对另一对象的访问。它与另外那个对象实现了同样的接口,并且会把任何方法调用传递给那个对象。另外那个对象通常称为本体(real subject)。代理可以代替其本体被实例化,并使其可被远程访问。
代理的结构:代理模式最基本的形式是对访问进行控制。代理对象和另一个对象(本体)实现的是同样的接口。实际上工作还是本体在做。它才是负责执行所分派的任务的那个对象或类。代理对象所做的不外乎节制对本体的访问。要注意,代理对象并不会在另一对象的基础上添加方法或修改其方法(就像装饰者那样),也不会简化那个对象的接口(就像门面元素那样)。它实现的接口与本体完全相同,所有对它进行的方法调用都会被传递给本体。
var obj = {
name : "zhangsan",
f1(){
console.log("f1函数");
},
f2(){
console.log("obj的f2函数");
},
talk(){
console.log("obj的talk函数");
}
}
//定义一个代理函数
function Proxy(target,options){
var temp = {};
//遍历要代理的对象
for(let attr in target){
//如果对象属性是一个函数
if(typeof target[attr] == "function"){
//空对象设定一个同名的属性,也是一个函数
temp[attr] = function(){
//如果代理对象也有这个属性函数
options[attr]?options[attr]():"";
target[attr]();
}
}
//如果对象属性为其他类型
else {
Object.defineProperty(temp,attr,{
//得到的是target的属性值
get(){
return target[attr];
},
//更改的也是target的属性值
set(val){
target[attr] = val;
}
});
}
}
return temp;
}
//
var proxy = new Proxy(obj,{
f2(){
console.log("这是f2代理方法");
},
talk(){
console.log("这是talk代理方法");
}
})
//通过代理对象来访问obj
proxy.f1();
proxy.f2();
proxy.talk();
3.工厂模式
定义:提供一个创建实例的功能,而无须关心其具体实现。被创建实例的类型可以是接口,抽象类或具体类。
本质: 内部主要实现的功能是“选择合适的实现类”。本质是“选择实现”。
//函数自调用 可以让外部访问不到 tanklist
var TankFactory = function(){
var tanklist = {
"天启" : function(){
this.name = "天启";
},
"幻影" : function(){
this.name = "幻影";
}
}
return {
create(type){
try{
return new tanklist[type]();
} catch(error){
console.info(`出现错误`);
return null;
}
}
};
}();
console.log(TankFactory.create("天启"));
console.log(TankFactory.create("犀牛"));
4.适配器模式
定义:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
本质 :转换匹配,复用功能。
适配器模式(Adapter)是将一个类(对象)的接口(方法或属性)转化成客户希望的另外一个接口(方法或属性) 适配器模式使得原本由于接口不兼容而不能一起工作的那些类(对象)可以一些工作。速成包装器(wrapper)
class Ipad {
playgame(){
console.log("可以玩游戏");
}
playmusic(){
console.log("可以听音乐");
}
}
class Iphone extends Ipad {
phonecall(){
console.log("可以打电话");
}
}
//适配器构造函数
function Adapter(target){
//代理模式
this.phonecall = function(){
target.phonecall?target.phonecall():console.info("该产品不支持打电话功能")
}
this.playmusic = function(){
target.playmusic?target.playmusic():console.info("该产品不支持放音乐功能")
}
this.playgame = function(){
target.playgame?target.playgame():console.info("该产品不支持玩游戏功能")
}
}
//
function test(product){
product.playgame();
product.playmusic();
product.phonecall();
}
test(new Adapter(new Ipad()));
test(new Adapter(new Iphone()));
5.观察者模式
定义:定义对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
本质:触发联动
当修改目标对象的状态的时候,就会触发相应的通知,然后会循环调用所有注册的观察者对象的相应方法,其实就相当于联动调用这些观察者的方法。
class Company{
constructor(){
this.emplist = new Map();
}
join(emp){
this.emplist.set(emp.no,emp);
}
leave(emp){
this.emplist.delete(emp.no);
}
pay(){
for(let [no,emp] of this.emplist){
emp.save(1000);
}
}
}
class Employee {
constructor(no){
this.no = no;
}
save(money){
console.log(`发工资了,我是编号${this.no}`+`工资为${money}`);
}
}
var JD = new Company();
var liu = new Employee(1);
var wang = new Employee(2);
var liu1 = new Employee(3);
var wang1 = new Employee(4);
JD.join(liu);
JD.join(wang);
JD.join(liu1);
JD.join(wang1);
JD.pay();