1. 程式人生 > >javascript設計模式

javascript設計模式

back inner names method build php ids opacity mon

  1. 單例模式(Singleton)
  2. 工廠模式(Factory)
  3. 橋接模式(Bridge)
  4. 組合模式(Composite)
  5. 門面模式(Facade)
  6. 適配器模式(Adapter)
  7. 裝飾者模式(Decorator)
  8. 享元模式(Flyweight)
  9. 代理模式(Proxy)
  10. 觀察者模式(Observer)
  11. 命令模式(Command)
下面代碼在ie6&ie6+&chrome測試通過,code地址: https://github.com/liuyanzhi08/javascript-design-pattern
轉載請註明出處: http://blog.csdn.net/nancle/article/details/24633191


1.單例模式(Singleton):
<html><head><title>Singleten-單例模式</title><meta charset="utf-8"></head>
<body>
	<script type="text/javascript">
	var MyNamespace = window.MyNamespace || {};
	// 定義在singleten模塊
	MyNamespace.singleten = (function(){
		var appid =  'helloJs';
		return {
			getAppId:function(){
				return appid;
			}
		};
	})();
	console.log(MyNamespace.singleten.getAppId());
	</script>
</body>
</html>

2.工廠模式(Factory)
<html><head><title>Factory-工廠模式</title><meta charset="utf-8"></head>
<body>
	<script type="text/javascript">
	var MyNamespace = window.MyNamespace || {};
	// 定義在xhr模塊 ,xhr事實上就是一個工廠,生產函數是getXHR
	MyNamespace.xhr = (function(){
		return {
			getXHR:function(){
				methods = [
					function(){ return new XMLHttpRequest(); },
					function(){ return new ActiveXObject('Microsoft.XMLHTTP'); },
					function(){ return new ActiveXObject('Msxml2.XMLHTTP'); }
				]
				for(var i = 0; i < methods.length; i++){
					try{
						methods[i]();
					}catch(e){
						continue;
					}
					this.getXHR = methods[i]();
					return methods[i]();
				}	
			}
		}
	})();

	alert(MyNamespace.xhr.getXHR());
	</script>
</body>
</html>

3.橋接模式(Bridge)
<html><head><title>Bridge-橋接模式</title><meta charset="utf-8"></head>
<body>
	<script type="text/javascript">
	var MyNamespace = window.MyNamespace || {};
	// 定義在request模塊 
	MyNamespace.request = (function(){
		function getXHR(){
			methods = [
				function(){ return new XMLHttpRequest(); },
				function(){ return new ActiveXObject('Microsoft.XMLHTTP'); },
				function(){ return new ActiveXObject('Msxml2.XMLHTTP'); }
			]
			for(var i = 0; i < methods.length; i++){
				try{
					methods[i]();
				}catch(e){
					continue;
				}
				this.getXHR = methods[i]();
				return methods[i]();
			}	
		}
		function handleReadystate(xhr, callback){
			xhr.onreadystatechange = function(){
				if(xhr.readyState == 4 && xhr.status == 200){
					if(callback){
						callback(xhr.responseText);
					}
				}
			}

		}	
		return function(method, uri, postData, callback){
			//此處運用了橋接模式
			var xhr = getXHR();
			xhr.open(method, uri, true);
			handleReadystate(xhr, callback);
			xhr.send(postData || null);
		}
	})();

	MyNamespace.request('post', 'test.php', "name=test&pwd=test", function(data){
		alert(data);
	})
	</script>
</body>
</html>

4.組合模式(Composite)
<html><head><title>Composite-組合模式</title><meta charset="utf-8"></head>
<body>
	<script type="text/javascript">
	var MyNamespace = window.MyNamespace || {};
	// 定義在form模塊
	MyNamespace.form = (function(){
		function Form(id, method, action){
			this.element = document.createElement('form');
			this.element.id = id;
			this.element.method = method;
			this.element.action = action;
			this.store = [];
		}
		Form.prototype = {
			add: function(fieldset){
				this.element.appendChild(fieldset.getDom());
				this.store.push(fieldset);
			},
			getDom: function(){
				return this.element;
			}
		}
		function Field(id){
			this.element = document.createElement('fieldset');
			this.element.id = id;
			this.store = [];
		}
		Field.prototype = {
			add: function(input){
				this.element.appendChild(input.getDom());
				this.store.push(input);
			},
			getDom: function(){
				return this.element;
			}
		}
		function Input(id, type, label){
			this.wrapper =  document.createElement('div');

			var labelTextNode = document.createTextNode(label);
			this.label = document.createElement('label');
			this.label.appendChild(labelTextNode);
			this.wrapper.appendChild(this.label);
		
			this.element = document.createElement(type);
			this.element.id = id;
			this.wrapper.appendChild(this.element);
		}
		Input.prototype = {
			getDom: function(){
				return this.wrapper;
			}
		}
		return{
			Form:Form,
			Field:Field,
			Input:Input
		}
	})();
	window.onload = function(){
			var form = new MyNamespace.form.Form('myForm', 'post', 'test.php');
			var fields = [
				new MyNamespace.form.Field('field1'),
				new MyNamespace.form.Field('field2'),
				new MyNamespace.form.Field('field3')
			];
			var inputs = [
				[
					new MyNamespace.form.Input('input1', 'input', 'input1:'),
					new MyNamespace.form.Input('input2', 'textarea', 'input2:'),
					new MyNamespace.form.Input('input3', 'input', 'input3:')
				],
				[
					new MyNamespace.form.Input('input4', 'textarea', 'input4:'),
					new MyNamespace.form.Input('input5', 'input', 'input5:'),
					new MyNamespace.form.Input('input6', 'input', 'input6:')
				],
				[
					new MyNamespace.form.Input('input7', 'input', 'input7:'),
					new MyNamespace.form.Input('input8', 'input', 'input8:'),
					new MyNamespace.form.Input('input9', 'textarea', 'input9:')
				]

			]
			for(var i = 0; i < fields.length; i++){
				form.add(fields[i]);
				for(var j = 0; j < inputs.length; j++){
					fields[i].add(inputs[i][j]);
				}
			}
			
			document.getElementsByTagName('body')[0].appendChild(form.getDom());
	}

	</script>
</body>
</html>

5.門面模式(Facade)
<html><head><title>Facade-門面模式</title><meta charset="utf-8"></head>
<body>
	<p id="greeting">Hello js!</p>
	<p id="greeting1">Hello js1!</p>

	<script type="text/javascript">
	var MyNamespace = window.MyNamespace || {};
	// 定義在even模塊
	MyNamespace.event = (function(){
		return {
			setStyle: function(ids, prop, value){
				for(var i = 0; i < ids.length; i++){
					document.getElementById(ids[i]).style[prop] = value;
				}
			},
			setCss: function(ids, styles){
				for(var prop in styles){
					if(!styles.hasOwnProperty(prop)){
						continue;
					}else{
						this.setStyle(ids, prop, styles[prop]);
					}
				}
			}
		}
	})();

	MyNamespace.event.setCss(['greeting', 'greeting1'], {
		'color': 'red',
		'background': 'green'
	})
	</script>
</body>
</html>

6.適配器模式(Adapter)
<html><head><title>Adapter-適配器模式</title><meta charset="utf-8"></head>
<body>
	<script type="text/javascript">
	var MyNamespace = window.MyNamespace || {};
	// 定義在sample模塊
	MyNamespace.sample = (function(){
		return {
			aFunctin: function(arg1, arg2, arg3){
				alert(arg1);
				alert(arg2);
				alert(arg3);
			},
			adapter: function(obj){
				var i = 0;
				var args = [];
				for(var prop in obj){
					if(!obj.hasOwnProperty(prop)) continue;
					args[i++] = obj[prop];
				}
				this.aFunctin(args[0], args[1], args[2]);
			}
		}
	})();

	// MyNamespace.sample.aFunctin('a', 'b', 'c');
	MyNamespace.sample.adapter({
		'arg1':'a',
		'arg2':'b',
		'arg3':'c'
	})
	</script>
</body>
</html>

7.裝飾者模式(Decorator)
<html><head><title>Decorator-裝飾者模式</title><meta charset="utf-8"></head>
<body>
	<script type="text/javascript">
	var MyNamespace = window.MyNamespace || {};
	// 定義在sample模塊
	MyNamespace.sample = (function(){
		function buildDom(){}
		buildDom.prototype = {
			startBuilt: function(){
				var body = document.getElementsByTagName('body')[0];
				for(var i = 0; i < 100; i++){
					var list = document.createElement('ul');
					for(var j = 0; j < 100; j++){
						var item = document.createElement('li');
						var text = document.createTextNode('test');
						item.appendChild(text);
						list.appendChild(item);
					}
					body.appendChild(list);
				}
			}
		}
		function timeDetector(buildDom){
			this.buildDom = buildDom;
			this.startTime;
		}
		timeDetector.prototype = {
			startRun: function(){
				this.startTime = (new Date()).getTime();
			},
			stopRun: function(){
				var runTime = (new Date()).getTime() - this.startTime;
				console.log("running cost:" + runTime + 'ms');
			},
			startBuilt: function(){
				this.startRun();
				this.buildDom.startBuilt();
				this.stopRun();
			}
		}
		return {
			buildDom: buildDom,
			timeDetector: timeDetector
		}
	})()

	window.onload = function(){
		var buildDom = new MyNamespace.sample.buildDom();
		var buildDom = new MyNamespace.sample.timeDetector(buildDom);
		buildDom.startBuilt();
	}
	</script>
</body>
</html>

8.享元模式(Flyweight)
<html><head><title>Flyweight-享元模式</title><meta charset="utf-8"></head>
<body>
	<style type="text/css">
		.month{width: 200px;height:150px;padding:10px;border: 1px solid green; float: left;margin-right: 5px;margin-bottom: 5px;}
		.day{width: 15px;border: 1px solid green;float: left;margin-right: 5px;margin-bottom: 5px;padding: 2px;text-align: center;}
	</style>
	<script type="text/javascript">
	var MyNamespace = window.MyNamespace || {};
	// 定義在calendar模塊
	MyNamespace.calendar = (function(){
		function Day(){}
		Day.prototype = {
			getDom: function(num){
				var element = document.createElement('div');
				element.className = 'day';
				var text = document.createTextNode(num);
				element.appendChild(text);
				return element;
			}
		}
		var flyWeightDay = new Day();
		function Year(year, parent) {
			this.element;
			this.parent = parent;
			this.isLeapYear = !(year%400) || (!(year%4) && (year%100));
			this.months = [];
			for(var i = 0; i < 12; i++){
				this.months.push(new Month(i, this.isLeapYear));
			}

			this.buildDom();
		}
		Year.prototype = {
			buildDom: function(parent){
				this.element = document.createElement('div');
				this.element.className = 'year';
				for(var i = 0; i < this.months.length; i++){
					var month = this.months[i];
					month.buildDom();
					this.element.appendChild(month.getDom());
				}
				this.parent.appendChild(this.element);
			}

		}
		function Month(month, isLeapYear){
			this.days = [];
			this.element;
			this.numDay;
			switch(month){
				case 0:
					this.numDay = 31;
					break;
				case 1:
					this.numDay = isLeapYear?

29:28; break; case 2: this.numDay = 31; break; case 3: this.numDay = 30; break; case 4: this.numDay = 31; break; case 5: this.numDay = 30; break; case 6: this.numDay = 31; break; case 7: this.numDay = 31; break; case 8: this.numDay = 30; break; case 9: this.numDay = 31; break; case 10: numDay = 30; break; case 11: this.numDay = 31; break; } } Month.prototype = { buildDom: function(){ this.element = document.createElement('div'); this.element.className = 'month'; for(var i = 0; i < this.numDay; i++){ this.element.appendChild(flyWeightDay.getDom(i+1)); } }, getDom: function(){ return this.element; } } return { Year:Year } })(); window.onload = function(){ var body = document.getElementsByTagName('body')[0]; new MyNamespace.calendar.Year(2004, body); } /****************************************************** * 非享元版:使用了幾百個Day對象,占用內存非常大 ***************************************/ // var MyNamespace = window.MyNamespace || {}; // // 定義在calendar模塊 // MyNamespace.calendar = (function(){ // function Year(year, parent) { // this.element; // this.parent = parent; // this.isLeapYear = !(year%400) || (!(year%4) && (year%100)); // this.months = []; // for(var i = 0; i < 12; i++){ // this.months.push(new Month(i, this.isLeapYear)); // } // this.buildDom(); // } // Year.prototype = { // buildDom: function(parent){ // this.element = document.createElement('div'); // this.element.className = 'year'; // for(var i = 0; i < this.months.length; i++){ // var month = this.months[i]; // month.buildDom(); // this.element.appendChild(month.getDom()); // } // this.parent.appendChild(this.element); // } // } // function Month(month, isLeapYear){ // this.days = []; // this.element; // var numDay; // switch(month){ // case 0: // numDay = 31; // break; // case 1: // numDay = isLeapYear?29:28; // break; // case 2: // numDay = 31; // break; // case 3: // numDay = 30; // break; // case 4: // numDay = 31; // break; // case 5: // numDay = 30; // break; // case 6: // numDay = 31; // break; // case 7: // numDay = 31; // break; // case 8: // numDay = 30; // break; // case 9: // numDay = 31; // break; // case 10: // numDay = 30; // break; // case 11: // numDay = 31; // break; // } // for(var i = 1; i <= numDay; i++){ // this.days.push(new Day(i)); // } // } // Month.prototype = { // buildDom: function(){ // this.element = document.createElement('div'); // this.element.className = 'month'; // for(var i = 0; i < this.days.length; i++){ // var day = this.days[i]; // day.buildDom(); // this.element.appendChild(day.getDom()); // } // }, // getDom: function(){ // return this.element; // } // } // function Day(num){ // this.num = num; // this.element; // } // Day.prototype = { // buildDom: function(){ // this.element = document.createElement('div'); // this.element.className = 'day'; // var text = document.createTextNode(this.num); // this.element.appendChild(text); // }, // getDom: function(){ // return this.element; // } // } // return { // Year:Year // } // })(); // window.onload = function(){ // var body = document.getElementsByTagName('body')[0]; // new MyNamespace.calendar.Year(2004, body); // } </script> </body> </html>


9.代理模式(Proxy)
<html><head><title>Proxy-代理模式</title><meta charset="utf-8"></head>
<body>
	<style type="text/css">
		body{padding: :0;margin:0;overflow: hidden;font-family: "微軟雅黑"}
		#modal-dialog{border: 3px solid green;padding: 10px;}
		#modal-close{position: absolute;top: -20px;right: -18px;cursor: pointer;border: 2px solid green;padding: 1px;border-radius:50% 50%;width: 15px;height: 15px;text-align: center;line-height: 12px;color: green;font-weight: bold;}
		#modal-loading{text-align: center;}
	</style>

	<script type="text/javascript">
	var MyNamespace = window.MyNamespace || {};
	// 定義在component模塊
	MyNamespace.component = (function(){
		function Modal(option){
		}
		Modal.prototype = {
			_addListener: function(){
				var that = this;
				window.onresize =  function(){
					that._resizeMask();
					that._repositionDialog();
				}
				this.closeBtn.onclick = function(){
					that.mask.parentNode.removeChild(that.mask);
					that.dialog.parentNode.removeChild(that.dialog);
				}
			},
			_resizeMask: function(){
				this.mask.style.width = '100%';
				this.mask.style.height = document.body.clientHeight;
			},
			_repositionDialog: function(){
				this.dialog.style.left = (document.body.clientWidth-this.dialog.offsetWidth)/2;
				this.dialog.style.top = (document.body.clientHeight-this.dialog.offsetHeight)/3;
			},
			show: function(){
				var body = document.getElementsByTagName('body')[0];
				//mask
				this.mask = document.createElement('div');
				this.mask.id = 'modal-mask';
				this.mask.style.position = 'absolute';
				this.mask.style.left = 0;
				this.mask.style.top = 0;
				this.mask.style.background = '#000';
				this.mask.style.opacity = '0.5';
				this.mask.style.filter = 'alpha(opacity=50)';
				this._resizeMask();
				body.appendChild(this.mask);
				//diaglog
				this.dialog = document.createElement('div');
				this.dialog.innerHTML = 'HELLO MODAL!';
				this.dialog.id = 'modal-dialog';
				this.dialog.style.position = 'absolute';
				//close-button
				this.closeBtn = document.createElement('div');
				var closeText = document.createTextNode('x');
				this.closeBtn.id = 'modal-close';  
				this.closeBtn.appendChild(closeText);
				this.dialog.appendChild(this.closeBtn);

				body.appendChild(this.dialog);
				this._repositionDialog();

				this._addListener();
			}
		}
		function ModalProxy(){
			this.interval = null;
			this.modal = new Modal();
			this._initialize();
		}
		ModalProxy.prototype = {
			_removeLoading: function(){
				this.mask.parentNode.removeChild(this.mask);
				this.loading.parentNode.removeChild(this.loading);
			},
			_resizeMask: function(){
				this.mask.style.width = '100%';
				this.mask.style.height = document.body.clientHeight;
			},
			_repositionLoading: function(){
				this.loading.style.left = (document.body.clientWidth-this.loading.offsetWidth)/2;
				this.loading.style.top = (document.body.clientHeight-this.loading.offsetHeight)/3;
			},
			_initialize: function(){
				var that = this;
				var body = document.getElementsByTagName('body')[0];
				//mask
				this.mask = document.createElement('div');
				this.mask.id = 'modal-loading-mask';
				this.mask.style.position = 'absolute';
				this.mask.style.left = 0;
				this.mask.style.top = 0;
				this.mask.style.background = '#000';
				this.mask.style.opacity = '0.5';
				this.mask.style.filter = 'alpha(opacity=50)';
				this._resizeMask();
				this.num = 0;
				body.appendChild(this.mask);
				//loading text
				this.loading = document.createElement('div');
				this.loading.innerHTML = 'loading...';
				this.loading.id = 'modal-loading';
				this.loading.style.position = 'absolute';

				body.appendChild(this.loading);
				this._repositionLoading();
				window.onresize =  function(){
					that._resizeMask();
					that._repositionLoading();
				}

				this.interval = setTimeout(function(){
					that._checkInitailization();
				}, 100);
			},
			_checkInitailization: function(callback){
				var that = this;
				this.num++;
				//這裏用num++ 來模擬等待數據處理的過程. this.num > 20為loading停止條件
				if(this.num > 20){
					clearTimeout(this.interval);
					this._removeLoading();
					callback();
				}else{
					document.title =  this.num;
					this.interval = setTimeout(function(){
						that._checkInitailization(callback)
					}, 100);					
				}
			},
			show: function(){
				var that = this;
				this._checkInitailization(function(){
					that.modal.show();

				});	
			}
		}
		return {
			ModalProxy:ModalProxy
		}
	})();

	window.onload = function(){
		var mp = new MyNamespace.component.ModalProxy();

		mp.show();

	}
	</script>


	1. Singleton - 單例模式<br/>
	2. Factory   - 工廠模式<br/>
	3. Bridge    - 橋接模式<br/>
	4. Composite - 組合模式<br/>
	5. Facade	 - 門面模式<br/>
	6. Adapter   - 適配器模式<br/>
	7. Decorator - 裝飾者模式<br/>
	8. Flyweight - 享元模式<br/>
	9. Proxy	 - 代理模式<br/>
</body>
</html>

10.觀察者模式(Observer)
<html><head><title>Observer-觀察者模式</title><meta charset="utf-8"></head>
<body>
	<script type="text/javascript">
	var MyNamespace = window.MyNamespace || {};
	// 定義在sample模塊 
	MyNamespace.sample = (function(){
		function Publisher(){
			this.subscribers = [];
		}
		Publisher.prototype = {
			publish: function(msg){
				for(var i in this.subscribers){
					this.subscribers[i].msg = msg;
				}
				alert('Publish:"'+msg+'"');
			}
		}
		function Subscriber(name){
			this.name = name;
			this.msg;
		}
		Subscriber.prototype = {
			subscribe: function(publisher){
				for(var i in publisher.subscribers){
					if(publisher.subscribers[i] == this){
						return;
					}
				}
				publisher.subscribers.push(this);
			},
			getMsg: function(){
				alert(this.name + ' has receive:"' + this.msg + '"');
			}
		}
		return {
			Publisher:Publisher,
			Subscriber:Subscriber
		}
	})();

	var p = new MyNamespace.sample.Publisher();
	var s1 = new MyNamespace.sample.Subscriber('s1');
	var s2 = new MyNamespace.sample.Subscriber('s2');
	var s3 = new MyNamespace.sample.Subscriber('s3');

	s1.subscribe(p);
	s2.subscribe(p);
	s3.subscribe(p);

	p.publish('new report');
	s1.getMsg();
	s2.getMsg();
	s3.getMsg();

	p.publish('another report')
	s1.getMsg();
	s2.getMsg();
	s3.getMsg();

	</script>
</body>
</html>

11.命令模式(Command)
<html><head><title>Command-命令模式</title><meta charset="utf-8"></head>
<body>
	<style type="text/css">
	.memu{}
	.menu-item{padding: 5px 10px; background: green;width: 100px;cursor: pointer;margin-bottom: 1px;}
	</style>
	<script type="text/javascript">
	var MyNamespace = window.MyNamespace || {};
	// 定義在composite模塊 
	MyNamespace.composite = (function(){
		function Menu(parent){
			this.parent = parent;
			this.element = document.createElement('div');
			this.element.className = 'menu';
			this.parent.appendChild(this.element);
		}
		Menu.prototype = {
			add: function(menuItem){
				this.element.appendChild(menuItem.element);
			}
		}
		function MenuItem(name, command){
			this.element = document.createElement('div');
			this.element.className = 'menu-item';
			var itemName = document.createTextNode(name)
			this.element.appendChild(itemName);
			this.command = command;
			this._addAction();
		}
		MenuItem.prototype = {
			_addAction: function(){
				var that = this;
				this.element.onclick = function(){
					that.command.run();
				}
			}
		}
		function Command(name){
			this.name = name;
		}
		Command.prototype = {
			run: function(){
				alert(this.name);
			}
		}
		return {
			Menu: Menu,
			MenuItem: MenuItem,
			Command: Command
		}
	})();

	window.onload = function(){
		var body = document.getElementsByTagName('body')[0];
		var menu = new MyNamespace.composite.Menu(body);
		var editCommand = new MyNamespace.composite.Command('edit');
		var saveCommand = new MyNamespace.composite.Command('save');
		var menuItem = new MyNamespace.composite.MenuItem('選項一', editCommand);
		var menuItem1 = new MyNamespace.composite.MenuItem('選項二', saveCommand);
		menu.add(menuItem);
		menu.add(menuItem1);
	}

	</script>
</body>
</html>




javascript設計模式