多態:同一操作作用於不同的對象上面,可以產生不同的解釋和不同的執行結果。
var makeSound = function (animal) {
if (animal instanceof Duck) {
console.log('嘎嘎嘎');
} else if (animal instanceof Chicken) {
console.log('咯咯咯');
}
};
var Duck = function () {};
var Chicken = function () {};
makeSound(new Duck()); // 嘎嘎嘎
makeSound(new Chicken()); // 咯咯咯
var makeSound = function (animal) {
animal.sound();
};
var Duck = function () {}
Duck.prototype.sound = function () {
console.log('嘎嘎嘎');
};
var Chicken = function () {}
Chicken.prototype.sound = function () {
console.log('咯咯咯');
};
makeSound(new Duck()); // 嘎嘎嘎
makeSound(new Chicken()); // 咯咯咯
- 類型檢查和多態:在靜態類型語言中編譯時會進行類型匹配檢查,不能給變量賦予不同類型的值所以需要向上轉型(當給一個類變量賦值時,這個變量的類型既可以使用這個類本身,也可以使用這個類的超類)。
- 使用繼承得到多態效果
- 繼承通常包括實現繼承和接口繼承。
- 實現繼承例子:
先創建一個Animal 抽象類,再分別讓Duck 和Chicken 都繼承自Animal 抽象類
public abstract class Animal {
abstract void makeSound(); // 抽象方法
}
public class Chicken extends Animal {
public void makeSound() {
System.out.println("咯咯咯");
}
}
public class Duck extends Animal {
public void makeSound() {
System.out.println("嘎嘎嘎");
}
}
Animal duck = new Duck(); // (1)
Animal chicken = new Chicken(); // (2)
public class AnimalSound {
public void makeSound(Animal animal) { // 接受Animal 類型的參數
animal.makeSound();
}
}
public class Test {
public static void main(String args[]) {
AnimalSound animalSound = new AnimalSound();
Animal duck = new Duck();
Animal chicken = new Chicken();
animalSound.makeSound(duck); // 輸出嘎嘎嘎
animalSound.makeSound(chicken); // 輸出咯咯咯
}
}
- JavaScript的多態
- 多態的思想實際上是把“做什麼”和“誰去做”分離開來。
- 在JavaScript 中,並不需要諸如向上轉型之類的技術來取得多態的效果。
- 多態在面向對象程序設計中的作用
- 《重構:改善既有代碼的設計》裏寫到:多態的最根本好處在於,你不必再向對象詢問“你是什麼類型”而後根據得到的答案調用對象的某個行爲——你只管調用該行爲就是了,其他的一切多態機制都會爲你安排妥當。
- 多態最根本的作用就是通過把過程化的條件分支語句轉化爲對象的多態性,從而消除這些條件分支語句。
- 地圖應用例子:
var googleMap = {
show: function () {
console.log('開始渲染谷歌地圖');
}
};
var baiduMap = {
show: function () {
console.log('開始渲染百度地圖');
}
};
var renderMap = function (map) {
if (map.show instanceof Function) {
map.show();
}
};
renderMap('google'); // 輸出:開始渲染谷歌地圖
renderMap('baidu'); // 輸出:開始渲染百度地圖
- 封裝:封裝的目的是將信息隱藏
- 封裝數據:JavaScript 並沒有提供對這些關鍵字的支持,我們只能依賴變量的作用域來實現封裝特性,而且只能模擬出public 和private 這兩種封裝性。例子:
var myObject = (function () {
var __name = 'sven'; // 私有(private)變量
return {
getName: function () { // 公開(public)方法
return __name;
}
}
})();
console.log(myObject.getName()); // 輸出:sven
console.log(myObject.__name) // 輸出:undefined
- 封裝類型:封裝類型是通過抽象類和接口來進行的。把對象的真正類型隱藏在抽象類或者接口之後,JavaScript 中,並沒有對抽象類和接口的支持。
- 封裝變化:封裝在更重要的層面體現爲封裝變化,《設計模式》一書曾提到如下文字,“考慮你的設計中哪些地方可能變化,這種方式與關注會導致重新設計的原因相反。它不是考慮什麼時候會迫使你的設計改變,而是考慮你怎樣才能夠在不重新設計的情況下進行改變。這裏的關鍵在於封裝發生變化的概念,這是許多設計模式的主題。”
- 原型模式和基於原型繼承的JavaScript對象系統:JavaScript 也同樣遵守這些原型編程的基本規則
- 所有的數據都是對象
- 基本類型包括undefined、number、boolean、string、function、object。
- JavaScript 中的根對象是Object.prototype 對象,Object.prototype 對象是一個空的對象。
- 要得到一個對象,不是通過實例化類,而是找到一個對象作爲原型並克隆它。