1. 程式人生 > >JavaScript基礎(十五)多型、多繼承、設計模式

JavaScript基礎(十五)多型、多繼承、設計模式

多型、多繼承、設計模式

多型

多型:同一個方法多種呼叫方式
例如:有一個需求——不傳引數返回10,1個引數返回10+引數,2個引數返回引數和

function add(){
	var args = arguments, len = arguments.length;
	switch(len){
		case 0:
			return 10;
		case 1:
			return
10 + args[0]; case 2: return args[0] + args[1]; } } console.log(add(), add(3), add(3, 14)); // 10 13 17 // 用多型實現 function Add(){ // 無引數 function zero(){ return 10; } // 一個引數 function one(num){ return 10 + num; } // 兩個引數 function two(num1, num2){ return num1 + num2; } // 相加共有的方法 this.add =
function(){ var args = arguments, len = arguments.length; switch(len){ case 0: return zero(); case 1: return one(args[0]); case 2: return two(args[0], args[1]); } } } // Test Code // 例項化物件 var instance = new Add(); console.log( instance.add(), instance.add(4), instance.add
(5, 8) ); // 10 14 13

多繼承

單繼承

只能覆蓋值型別

var json1 = {name: 'aaa', age: 30};
var json2 = {name: 'bbb', age: 20, key: 8888};
function merge(json1, json2){
	for(var key in json2){
		json1[key] = json2[key];
	}
	return json1;
}
console.log(merge(json1, json2)); // {name: "bbb", age: 20, key: 8888}
// 需求:如果有多個引數(大於2兩個)需要合併引數呢?

多繼承

function merge(){
	var args = arguments, len = arguments.length;
	target = args[0];
	for(var i=1; i<len; i++){
		var obj = args[i];
		for(var key in obj){
			target[key] = obj[key];
		}
	}
	return target;
}
// Test Code
var json1 = {name: 'aaa', age: 30};
var json2 = {name: 'bbb', age: 20, key: 8888};
var json3 = {name: 'ccc', hobby: 'basketball'};
console.log( merge(json1, json2, json3) ); // {name: "ccc", age: 20, key: 8888, hobby: "basketball"}

應用:彈窗元件

function oTab(json){
	var defaults = { 
		title: 'Title',
		width: 100,
		height: 100,
		background: 'grey'
	};
	merge(defaults, json); 
	// $.extend({}, defaults,json);
}
oTab({
	width: 200,
	height: 200,
	title: 'Hello world!',
	background: 'red'
});
// $.extend({}, json1, json2, json3, ...);

設計模式

簡單工廠

簡單工廠模式
又叫靜態工廠模式,由一個物件決定建立某一種產品物件類的例項,主要用來建立同一類的物件

// 舉例
// 籃球類相關
var Basketball = function(){
	this.info = '籃球盛行於美國';
}
Basketball.prototype = {
	getMember: function(){
		console.log('每個隊伍5人');
	},
	getBallSize: function(){
		console.log('標準籃球直徑(dB)為 24.6釐米');
	}
}
// 足球類相關
var Football = function(){
	this.info = '足球盛行於巴西';
}
Football.prototype = {
	getMember: function(){
		console.log('每個隊伍11人');
	},
	getBallSize: function(){
		console.log('標準足球直徑約21釐米左右')
	}
}
// 以此類推,還有很多其他類。。。
// 這個時候就可以使用“工廠模式”啦,例如
// 定義以一個運動工廠類
var SportsFactory = function(name){
	switch(name){
		case 'NBA': return new Basketball();
		case 'WorldCup': return new Football();
	}
}
// Test Code
var football = SportsFactory('WorldCup');
console.log(football.info);	// 足球盛行於巴西
football.getMember();	// 每個隊伍11人
football.getBallSize();	// 標準足球直徑約21釐米左右

安全工廠

// 舉例
var Java = function(content){
	this.content = content;
	(function(content){
		var div = document.createElement('div');
		div.innerHTML = content;
		div.style.color = 'red';
		document.getElementById('container').appendChild(div);
	})(content);
}
// Java('你好');
new Java('Hello, world!');
// 如果又有一個Php
var Php = function(content){
	this.content = content;
	(function(content){
		var div = document.createElement('div');
		div.innerHTML = content;
		div.style.color = 'blue';
		document.getElementById('container').appendChild(div);
	})(content);
}
new Php('hahahahahahaha!');

// 簡單工廠
function JobFactory(type, content){
	switch(type){
		case 'java': return new Java(content);
		case 'php': return new Php(content);
	}
}
JobFactory('java', 'Java is very good');
/*
問題:每次如果有新的型別type,都需要在case里加一項,並且實現對應的類
*/
var Factory = function(type, content){
	return new this[type](content);
};
// 在工廠的原型上繫結屬性和方法
Factory.prototype = {
	Java: function(content){
		this.content = content;
		(function(content){
			var div = document.createElement('div');
			div.innerHTML = content;
			div.style.color = 'red';
			document.getElementById('container').appendChild(div);
		})(content);
	},
	Php: function(content){
		this.content = content;
		(function(content){
			var div = document.createElement('div');
			div.innerHTML = content;
			div.style.color = 'blue';
			document.getElementById('container').appendChild(div);
		})(content);
	},
	Python: function(content){
		this.content = content;
		(function(content){
			var div = document.createElement('div');
			div.innerHTML = content;
			div.style.color = 'green';
			document.getElementById('container').appendChild(div);
		})(content);
	}
}
// 這樣以後如果有新的型別了,只需要在工廠的原型物件上進行新增就可以了
var php = new Factory('Php', 'abcdefg');
var python = new Factory('Python', 'dasfjdsfljl');
// 但是如果不寫new,例如
var python = Factory('Python', 'rqewrwqyi'); // Uncaught TypeError: this[type] is not a constructor
// 這樣就不安全了,==> 安全工廠

安全工廠實現

// 安全工廠
Factory = function(type, content){
	console.log(this);
	if(this instanceof Factory){
		return new this[type](content);
	}else{
		return new Factory(type, content);
	}
};
// 在工廠的原型上繫結屬性和方法
Factory.prototype = {
	Java: function(content){
		this.content = content;
		(function(content){
			var div = document.createElement('div');
			div.innerHTML = content;
			div.style.color = 'red';
			document.getElementById('container').appendChild(div);
		})(content);
	},
	Php: function(content){
		this.content = content;
		(function(content){
			var div = document.createElement('div');
			div.innerHTML = content;
			div.style.color = 'blue';
			document.getElementById('container').appendChild(div);
		})(content);
	},
	Python: function(content){
		this.content = content;
		(function(content){
			var div = document.createElement('div');
			div.innerHTML = content;
			div.style.color = 'green';
			document.getElementById('container').appendChild(div);
		})(content);
	}
}
var python = Factory('Python', '123134');

抽象工廠

抽象工廠設計模式:
通過對類的工廠抽象使其業務用於對產品簇的建立,而不負責建立某一類產品的例項
抽象類:
是一種宣告但不能使用的類,當你使用的時候就會報錯。所以我們可以在類的方法中手動的丟擲錯誤來模擬抽象類
// 汽車抽象類(模擬)
var Cat = function(){}
Cat.prototype = {
	getPrice: function(){
		return new Error("抽象方法不能使用");
	},
	getSpeed: function(){
		return new Error("抽象方法不能使用");
	}
}
var cat = new Cat();
// alert(cat.getPrice()); // Error: 抽象方法不能使用
// alert(cat.getSpeed()); // Error: 抽象方法不能使用

// 抽象工廠方法
var AbstractFactory = function(subType, superType){//子類名稱,父類[抽象類]的名稱
	// 判斷抽象工廠中是否有該抽象類
	if(typeof AbstractFactory[superType] === 'function'){
		// 過渡類
		function F(){};
		// 繼承父類的屬性和方法
		F.prototype = new AbstractFactory[superType]();
		// 子類原型繼承父類
		subType.prototype = new F();
		// 修正子類原型的構造器
		subType.prototype.constructor = subType;
	}else{
		throw new Error('不存在抽象類');
	}
}
// 小汽車抽象類
AbstractFactory.Car = function(){
	this.type = "Car";
}
AbstractFactory.Car.prototype = {
	getPrice: function(){
		return new Error("抽象方法不能使用");
	},
	getSpeed: function(){
		return new Error("抽象方法不能使用");
	}
}
// 寶馬汽車子類
function BWM(price, speed){
	this.price = price;
	this.speed = speed;
}
// 寄生組合式繼承
AbstractFactory(BWM, 'Car');
BWM.prototype.getPrice = function(){
	return this.price;
}

var bwm = new BWM(100000, 1000);
console.log(bwm.getPrice(), bwm.getSpeed(), bwm.constructor);
// 100000    Error: 抽象方法不能使用 at BWM.getSpeed   ƒ Object() { [native code] }

		BWM.prototype.getSpeed = function(){
	return this.speed;
}
// 這個時候就可以呼叫getSpeed()方法了
console.log(bwm.getPrice(), bwm.getSpeed(), bwm.constructor);
// 100000 1000 ƒ Object() { [native code] }
// 修正子類原型的構造器
// subType.prototype.constructor = subType;
// 之後
console.log(bwm.constructor.name); // BWM

介面卡模式

將一個類(物件)的介面轉換成另一個介面,以滿足使用者的需求,使得類(物件)之間的不相容問題得以解決
例如

// 適配異類框架,如適配A類框架(假設這是自己用的一個框架),用jQuery
var A = A || {};
// 通過id獲取元素物件
A.g = function(id){
	return document.getElementById(id);
};
// 為元素繫結事件
A.on = function(id, type, fn){
	// 若傳遞引數id是字串,否則以元素物件處理
	var dom = typeof id === 'string' ? this.g(id) : id;
	if(dom.addEventListener){
		dom.addEventListener(type, fn, false);
	}else if(dom.attachEvent){
		// IE8及其以下版本
		dom.attachEvent('on' + type, fn);
	}else{
		// 早期的瀏覽器
		dom['on'+type] = fn;
	}
}
// 視窗