javascript设计模式18状态模式

态模式是一种容易被忽略或者被低估的模式,但却是一种非同寻常的优秀模式。一般对象都会有一些状态,而状态的改变往往会影响对象的行为。
平时工作中,我们倾向于在对象中对状态做if else判断,而后去执行相应的动作。例如电灯对象的开关两种状态的切换。
当我们试图用状态模式去重构一般实现的时候,便会发现状态模式的好处。
状态模式,把对象的不同状态和其对应的行为封装在一起,在对象上下文中,把请求委托给状态对象,有效的消除了对象上下文中大量的ifelse分之语句

var light = function(){
	this.offstate = new OffState(this)
	this.onState = new OnState(this)
	this.curState = this.offstate
}

light.prototype.buttonWasPressed = function(){
	this.curState.buttonWasPressed()
}

light.prototype.SetState = function(state){
	this.curState = state
}

var OffState = function(light){
	this.light = light;
}

OffState.prototype.buttonWasPressed = function(){
	console.log('开灯')
	this.light.SetState(this.onState)
}

// 模拟状态抽象类
var State = function(){

}

State.prototype.buttonWasPressed  = function(){
	throw new Error("父类的buttonWasPressed必须被重写")
}

OffState.prototype = new State()

  

优缺点:
定义了状态和行为之间的关系,并把它们封装到一个类里。通过增加新的状态类,很容易增加新的状态和转换
避免context无限膨胀,状态切换的逻辑分布在状态类中,去掉了context中原本过多的条件分支
用对象代替字符串记录当前状态,使状态切换更加一目了然
context中请求动作和状态类中封装的行为可以非常容易的独立变化而互不影响。
缺点:系统中会定义许多状态类,编写多个类是一项枯燥乏味的工作,增加很多对象。逻辑分散在各个状态类中,无法在一个地方就看出整个状态机的逻辑。

性能优化点:
大量相似的状态对象,可以考虑使用享元模式
状态类对象的创建可以考虑使用延迟加载或者一次加载

和策略模式的关系:
从结构上看 ,两者几乎一样,都需要一个context和一系列状态或策略对象,需要将请求委托给这些对象。
但是意图完全不同,策略模式主要用来封装算法,对象之间的平行的关系,对同一个结果的不同实现,客户需要了解每个策略对象的细节和功能才能按需使用。
状态则用来封装状态和行为,什么样状态对应什么样行为,是确定好的,改变行为发生在状态模式内部,对客户来说不用了解这些细节。

js版本的状态机,使用对象字面量封装状态机

var light = function(){
	this.curState = FSM.off;
}

light.prototype.init = function(){
	var button = document.createElement('button'),
	self = this

	button.innerHTML='已关灯'
	this.button = document.body.appendChild(button)
	this.button.onclick = function(){
		self.curState.buttonWasPressed.call(self)
	}
}
var  FSM= {
	off:{
		buttonWasPressed:function(){
			console.log('开灯')
			this.curState = FSM.on
		}
	},
	on:{
		buttonWasPressed:function(){
			console.log('关灯')
			this.curState  = FSM.off
		}
	}
}
var light = new light()
light.init()

var StateFactory= (function(){
	var State = function(){}
	State.prototype.buttonWasPressed = function(){
		throw new Error('子类必须重写父类的buttonWasPressed')
	}

	return function(param){
		var F = function(light){
			this.light = light
		}
		F.prototype = new State();
		for(var i in param){
			F.prototype[i] = param[i]
		}
		return F;
	}
})()

var offState = StateFactory({buttonWasPressed:function(){
	console.log('开灯')
	this.curState =  this.onState;
}})

var light = function(){
	this.offState = new offState(this)
	this.onState = new onState(this)
	this.curState = this.offState;
} 
light.prototype.init = function(){
	var button = document.createElement('button'),
	self = this

	button.innerHTML='已关灯'
	this.button = document.body.appendChild(button)
	this.button.onclick = function(){
		self.curState.buttonWasPressed()
	}
}
light.init()

  

posted @ 2016-02-24 14:08  倾其一生  阅读(1033)  评论(0)    收藏  举报