工厂模式
1. 简单工厂
简单工厂:使用一个类或对象封装实例化操作
var Speedster = function() {}
Speedster.prototype = {
assemble: function() {}
}
var ComfortCruiser = function() {}
ComfortCruiser.prototype = {
assemble: function() {}
}
// 简单工厂模式
var BicycleFactory = {
createBicycle: function(model) {
var bicycle;
switch(model) {
case ‘The Speedster‘:
bicycle = new Speedster();
break;
case ‘The Comfort Cruiser‘:
default:
bicycle = new ComfortCruiser()
}
//检查是否实现了相应父类的方法
// Interface.ensureImplement(bicycle, Bicycle)
return bicycle
}
}
var BicycleShop = function() {};
BicycleShop.prototype = {
sellBicycle: function(model) {
var bicycle = BicycleFactory.createBicycle(model);
bicycle.assemble()
return bicycle
}
}
// usage
var shop = new BicycleShop()
var b1 = shop.sellBicycle(‘aaaa‘)
// 可提供车型的所有信息都集中在一个地方管理
2. 工厂模式
这里的工厂指的是一个将其成员对象的实例化推迟到子类中进行的类
var AcmeSpeedster = function() {}
AcmeSpeedster.prototype = {
assemble: function() {}
}
var AcmecomfortCruiser = function() {}
AcmecomfortCruiser.prototype = {
assemble: function() {}
}
// BicycleShop 就是一个工厂,它是一个抽象类,需要在继承后实现里面用于实例化的工厂方法
var BicycleShop = function() {};
BicycleShop.prototype = {
sellBicycle: function(model) {
var bicycle = this.createBicycle(model)
bicycle.assemble()
return bicycle;
},
// 工厂方法
createBicycle: function(model) {
throw new Error(‘Unsupported operation on an abstract class.‘)
}
}
var AcmeBicycleShop = function() {};
extend(AcmeBicycleShop, BicycleShop);
AcmeBicycleShop.prototype.createBicycle = function(model) {
var bicycle;
switch(model) {
case ‘The Speedster‘:
bicycle = new AcmeSpeedster();
break;
case ‘The Comfort Cruiser‘:
default:
bicycle = new AcmecomfortCruiser();
}
// Interface.ensureImplement(bicycle, Bicycle)
return bicycle
}
// usage
var ashop = new AcmeBicycleShop()
ashop.sellBicycle()
// 对 Bycycle 进行一般性操作的代码可以全部写在父类 BicycleShop 中,而具体的 Bicycle 对象进行实例化的工作则别留到子类中。
3. 示例:XHR工厂
var SimpleHandle = function() {};
SimpleHandle.prototype = {
require: function(method, url, callback, postVars) {
var xhr = this.createXhrObject();
xhr.onreadystatechange = function() {
if(xhr.readyState !== 4) return;
(xhr.status === 200) ?
callback.success(xhr.responseText, xhr.responseXML):
callback.failure(xhr.status);
}
xhr.open(method, url, true);
if(method != ‘POST‘) postVars = null;
xhr.send(postVars)
},
createXhrObject: function() {
var methods = [
function() { return new XMLHttpRequest() },
function() { return new ActiveXObject(‘Msxml2.XMLHTTP‘) },
function() { return new ActiveXObject(‘Microsoft.XMLHTTP‘) }
];
for(var i=0, len=methods.length; i<len; i++) {
try {
methods[i]();
} catch(err) {
continue;
}
// memoizing : 返回所创建的对象并将自身改为用以创建那个对象的函数
this.createXhrObject = methods[i]
return methods[i]()
}
throw new Error(‘SimpleHandle: Could not create an XHR object.‘)
}
}
# usage
var myHandler = new SimpleHandle();
var callback = {
success: function(responseText) {alert(‘Success: ‘ + responseText)},
failure: function(statusCode) {alert(‘Failure: ‘ + statusCode)}
}
myHandler.require(‘POST‘, ‘http://www.baidu.com‘, callback)
4. 示例 :RSS阅读器
var SimpleHandle = function() {};
SimpleHandle.prototype = {
require: function(method, url, callback, postVars) {
var xhr = this.createXhrObject();
xhr.onreadystatechange = function() {
if(xhr.readyState !== 4) return;
(xhr.status === 200) ?
callback.success(xhr.responseText, xhr.responseXML):
callback.failure(xhr.status);
}
xhr.open(method, url, true);
if(method != ‘POST‘) postVars = null;
xhr.send(postVars)
},
createXhrObject: function() {
var methods = [
function() { return new XMLHttpRequest() },
function() { return new ActiveXObject(‘Msxml2.XMLHTTP‘) },
function() { return new ActiveXObject(‘Microsoft.XMLHTTP‘) }
];
for(var i=0, len=methods.length; i<len; i++) {
try {
methods[i]();
} catch(err) {
continue;
}
// memoizing : 返回所创建的对象并将自身改为用以创建那个对象的函数
this.createXhrObject = methods[i]
return methods[i]()
}
throw new Error(‘SimpleHandle: Could not create an XHR object.‘)
}
}
var ListDisplay = function(id, parent) {
this.list = document.createElement(‘ul‘);
this.list.id = id;
parent.appendChild(this.list)
}
ListDisplay.prototype = {
append: function(text) {
var newEl = document.createElement(‘li‘);
this.list.appendChild(newEl);
newEl.innerhtml = text;
return newEl
},
remove: function(el) {
this.list.removeChild(el);
},
clear: function() {
this.list.innerHTML = ‘‘;
}
}
var FeedReader = function(display, xhrHandler, conf) {
this.display = display;
this.xhrHandler = xhrHandler;
this.conf = conf;
this.startUpdates();
}
FeedReader.prototype = {
fetchFeed: function() {
var that = this;
var callback = {
success: function(text, xml) {
that.parseFeed(text, xml)
},
failure: function(status) {
that.showError(status)
}
}
this.xhrHandler.require(‘GET‘, this.conf.feedUrl, callback);
},
parseFeed: function(responseText, responseXML) {
this.display.clear()
var items = responseXML.getElementsByTagName(‘item‘);
for(var i=0, len=items.length; i<len; i++) {
var title = items[i].getElementsByTagName(‘title‘)[0];
var link = items[i].getElementsByTagName(‘link‘)[0];
this.display.append(‘<a href="‘ + link.firstChild.data + ‘">‘+ title.firstChild.data + ‘</a>‘ )
}
},
showError: function(statusCode) {
this.display.clear();
this.display.append(‘Error fetching feed.‘)
},
stopUpdates: function() {
clearInterval(this.interval);
},
startUpdates: function() {
this.fetchFeed();
var that = this;
this.interval = setInterval(function() {
that.fetchFeed();
}, this.conf.updateInterval * 1000)
}
}
var FeedManager = {
createFeedReader: function(conf) {
var displayModule = new ListDisplay(conf.id + ‘-display‘, conf.parent)
// Interface.ensureImplements(displayModule, DisplayModule)
var xhrHandler = new SimpleHandle()
// Interface.ensureImplements(xhrHandler, AjaxHandler)
return new FeedReader(displayModule, xhrHandler, conf)
}
}
var conf = {
id: ‘cnn-top-stories‘,
feedUrl: ‘https://laike9m.com/blog/rss/‘, //http://www.adaymag.com/feed/‘,
updateInterval: 60,
parent: document.getElementById(‘feed-readers‘)
}
// usage
FeedManager.createFeedReader(conf)
5. 工厂模式的适用场合
- 动态实现
- 创建一些用不同方法实现统一接口的对象(如上面自行车例子)
- 可明确的实现统一接口【自行车】,也可隐含的实现(根据网速等环境原因) 【XHR 工厂】
- 节省设置开销
- 把实例化对象时重复的操作集中在一个地方
- 用许多小型对象组成一个大对象 【FeedMabage】
6. 工厂模式之弊
- 如果不会另外更换一个类,或者不需要在运行期间在一系列可互换的类中进行选择,那就不应该使用工厂方法
- 使用 new 实例化可以让代码更简单易懂
- 切勿滥用,如果拿不定主意,那就不要用,因为在重构代码的时候还有机会使用
注意
转载、引用,但请标明作者和原文地址