2. JavaScript 设计模式(简单工厂,工厂方法,抽象工厂)

本文详细介绍了简单工厂、工厂方法和抽象工厂三种设计模式,并通过具体的JavaScript示例解释了它们的应用场景和实现方式。
  1. 简单工厂(simple factory)

简单工厂模式:又叫静态工厂方法,由一个工厂对象觉得创建某一种产品对象类的实例。主要用于创建同一类对象。

  • 简单工厂 uml 图格式如下:
    这里写图片描述

    由上面的uml图可知,工厂返回的对象是要继承Product类的,但是由于js定义变量是没有指定数据类型,也没有多态。那怎么怎么保证工厂返回的对象都继承Product呢?我自己想到了一个方法。

/**
 * 披萨基类
 *
 * @constructor
 */
var Pizza = function() {
    this.getName = function() {
        console.log('披萨类!');
        // 抛出错误,模拟抽象类
        throw new Error('该类为抽象类,不能条用方法!');
    };
};

/**
 * 芝士披萨类
 *
 * @constructor
 */
var CheesePizza = function() {};
// 继承皮萨类
CheesePizza.prototype = new Pizza();
// 重写 getName 方法
CheesePizza.prototype.getName = function() {
    console.log('芝士披萨类');
};

var ClamPizza = function() {};
ClamPizza.prototype = new Pizza();
ClamPizza.prototype.getName = function() {
    console.log('蛤蜊披萨')
};


/**
 * 工厂方法
 *
 * @constructor
 */
var simplePizzaFactory = function(type) {
    var pizza = null;
    if (type == 'cheese') {
        pizza = new CheesePizza();
    } else if (type == 'clam') {
        pizza = new ClamPizza();
    }

    var superObj = pizza.__proto__;
    if (!superObj instanceof Pizza) {
        throw new Error('该类的产品没有继承 Pizza 类!');
    }
    return pizza;
};


var cheesePizza = simplePizzaFactory('cheese');
cheesePizza.getName(); // console: 芝士披萨类
  • 利用__proto__这个就保证了工厂返回的类都是继承与Pizza(图为Product)类的。

2.工厂方法(factory method)

通过对产品类的抽象使其创建业务主要负责用于创建多类产品的实例。

  • 工厂方法 uml 图如下:
    这里写图片描述

  • 工厂类代码,这里只有“纽约pizza工厂”其实还可以有“墨西哥pizza工厂”甚至还可以有其他的。不写了,就举个例子吧。

/**
 * Pizza 工厂抽象类
 *
 * @constructor
 */
var PizzaFactory = function() {
    this.createPizza = function(type) {
        throw new Error('该 pizza 工厂类用于继承,不能调用');
    };
};

/**
 * 纽约 pizza 工厂类
 *  * @constructor
 */
var NYPizzaFactory = function() {};
NYPizzaFactory.prototype = new PizzaFactory();
NYPizzaFactory.prototype.createPizza = function(type) {
    var pizza = null;
    if (type == 'cheese') {
        pizza = NYCheesePizza();
    } else if (type == 'clam') {
        pizza = NYClamPizza();
    }
	
	var superObj = pizza.__proto__;
    if (!superObj instanceof Pizza) {
        throw new Error('该类的产品没有继承 Pizza 类!');
    }
    return pizza;
};
  • pizza 类代码
/**
 * Pizza 抽象类
 *
 * @constructor
 */
var Pizza = function() {
    this.getName = function() {
        throw new Error('该 pizza 类用于继承,不能调用');
    };
};

/**
 * 纽约芝士披萨类
 *
 * @constructor
 */
var NYCheesePizza = function() {};
NYCheesePizza.prototype = new Pizza();
NYCheesePizza.prototype.getName = function() {
    console.log('纽约芝士披萨!');
};

/**
 * 纽约蛤蜊披萨类
 *
 * @constructor
 */
var NYClamPizza = function() {};
NYClamPizza.prototype = new Pizza();
NYClamPizza.prototype.getName = function() {
    console.log('纽约蛤蜊披萨!');
};

3.抽象工厂模式(abstract factory)

通过对类的工厂抽象使其业务用于对产品类簇的创建。而不是负责创建一类产品的实例。

  • 抽象工厂 uml 图如下:
    这里写图片描述

将抽象工厂和工厂方法的 uml 图比较一下,可以发现工厂方法用来生成不同的pizza。而抽象工厂则是生产一个一地方的披萨店的所有产品。举个例子,ProductA是pizza,ProductB是薯条。

  • pizza 类代码(和上面的一样,没有区别)
/**
 * 披萨基类
 *
 * @constructor
 */
var Pizza = function() {
    this.getName = function() {
        throw new Error('该 pizza 类用于继承,不能调用');
    }
};

/**
 * 纽约芝士披萨类
 *
 * @constructor
 */
var NYCheesePizza = function() {};
NYCheesePizza.prototype = new Pizza();
NYCheesePizza.prototype.getName = function() {
    console.log('纽约芝士披萨!');
};

/**
 * 纽约蛤蜊披萨类
 *  * @constructor
 */
var NYClamPizza = function() {};
NYClamPizza.prototype = new Pizza();
NYClamPizza.prototype.getName = function() {
    console.log('纽约蛤蜊披萨!');
};
  • 薯条类代码
/**
 * 薯条基类
 *
 * @constructor
 */
var Fries = function() {
    this.getName = function() {
        throw new Error('该薯条类用于继承,不能调用');
    };
};

/**
 * 配番茄酱的薯条
 *
 * @constructor
 */
var TomatoFries = function() {};
TomatoFries.prototype = new Fries();
TomatoFries.prototype.getName = function() {
    console.log('配番茄酱的薯条');
};

/**
 * 配芝士的薯条
 *  * @constructor
 */
var CheeseFries = function() {};
CheeseFries.prototype = new Fries();
CheeseFries.prototype.getName = function() {
    console.log('配芝士的薯条');
};
  • 商店工厂类(这里除了纽约,还有其他的商店可以继续写,例如墨西哥。。。)
/**
 * 商店工厂抽象类
 *
 * @constructor
 */
var StoreFactory = function() {
    this.createPizza = function(type) {
        throw new Error('该商店工厂类用于继承,不能调用');
    };
    this.createFries = function(type) {
        throw new Error('该商店工厂类用于继承,不能调用');
    };
};

/**
 * 纽约商店工厂类
 *  * @constructor
 */
var NYFactory = function() {};
NYFactory.prototype = new StoreFactory();
NYFactory.prototype.createPizza = function(type) {
    var pizza = null;
    if (type == 'cheese') {
        pizza = NYCheesePizza();
    } else if (type == 'clam') {
        pizza = NYClamPizza();
    }

	var superObj = pizza.__proto__;
    if (!superObj instanceof Pizza) {
        throw new Error('该类的产品没有继承 Pizza 类!');
    }
    return pizza;
};
NYFactory.prototype.createFries = function() {
    // 偷个懒不写了
};

4.总结(摘自Head First 设计模式):

  • 所有的工厂都是用来封装对象的创建。
  • 简单工厂,虽然不是真正的设计模式,但仍不失为一个简单的方法,可以将客户程序从具体类解耦。
  • 工厂方法使用继承,把对象的创建委托给子类,子类实现工厂来创建对象。
  • 抽象工厂使用对象组合,对象的创建被实现在工厂接口所暴露的方法中。
  • 所有工厂模式都是通过减少应用程序和具体类之间的依赖促进松耦合。
  • 工厂方法允许类将实例化延迟到子类进行。
  • 抽象工厂创建相关的对象家族,而不需要依赖他们的具体类。
  • 依赖倒置原则,指导我们避免依赖具体类,而要尽量依赖抽象
  • 工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体类编程。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Media(中介者)模式</title> <script type="text/javascript" src="js/jquery.js"></script> </head> <body> <h2>Media(中介者)模式</h2> <p>行为设计模式。公开一个统一的接口,系统的不同部分可以通过该接口进行通信。</p> <p>确保组件的交互是通过这个中心点来处理,而不是通过显示地引用彼此。</p> <p>这种模式可以帮助我们解耦系统并提高组件的可重用性</p> <hr> <script> // 1 基本实现 var mediator = (function (){ // 存储可被广播或监听的topic var topics = {}; // 订阅一个topic,提供一个回调函数,一旦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; } // call 和 apply 方法都是用来调用“不属于自身的方法”,apply第二参数必须是数组 // 下面的代码相当于 arguments.slice,但是arguments本身没有 slice方法 // slice 方法是用来截取数组 // arguments 是实参“数组” args = Array.prototype.slice.call(arguments, 1); for(var i = 0, l = topics[topic].length; i < l; i++){ var subscription = topics[topic][i]; subscription.callback.apply(subscription.context, args); // subscription.callback(arguments[1]); } return this; }; return { publish: publish, subscribe: subscribe, installTo: function (obj){ obj.subscribe = subscribe; obj.publish = publish; } } })(); </script> <h3>简单实现</h3> <form id="chatForm"> <label for="fromBox">Your Name:</label> <input id="fromBox" type="text"> <br> <label for="toBox">Send to:</label> <input id="toBox" type="text"> <br> <label for="chatBox">Message:</label> <input id="chatBox" type="text"> <button action="submit">Chat</button> </form> <div id="chatResult"></div> <script type="text/javascript"> $("#chatForm").on("submit", function (e){ e.preventDefault(); // 从UI上获取chat的数据 var text = $("#chatBox").val(), from = $("#fromBox").val(), to = $("#toBox").val(); // 将数据发布到newMessage主题上 mediator.publish("newMessage", {message: text, from: from, to: to}); }); // 将新信息附加到聊天记录结果上 function displayChat(data){ var date = new Date(), msg = data.from + " said \""+data.message+"\" to "+ data.to; $("#chatResult").prepend(""+msg+" ("+date.toLocaleTimeString()+")"); } // 记录消息日志 function logChat(data){ if(window.console){ console.log(data); } } // 通过mediator订阅提交的newMessage主题 mediator.subscribe("newMessage", displayChat); mediator.subscribe("newMessage", logChat); </script> </body> </html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值