設(shè)計模式
開題先說明一下奥此,設(shè)計模式告訴我們?nèi)绾谓M織類和對象以解決某種問題。讓代碼變得更加優(yōu)雅是我們責(zé)無旁貸的任務(wù)
策略模式
- 設(shè)計原則
多用組合稚虎,少用繼承
為什么要如此做,下面會做出解釋序攘,現(xiàn)在心里先存著這個念頭
talk is cheap,show me you code
// 飛行接口
public interface FlyBehavior {
public void fly();
}
//叫聲接口
public interface QuackBehavior {
public void quack();
}
//不會飛行的實現(xiàn)
public class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
System.out.println("I can't fly");
}
}
//可以用翅膀飛行的實現(xiàn)
public class FlyWithWings implements FlyBehavior{
@Override
public void fly() {
System.out.println("I'm flying");
}
}
//不會叫的實現(xiàn)
public class MuteQuack implements QuackBehavior {
@Override
public void quack() {
System.out.println("slience");
}
}
//會叫的實現(xiàn)
public class Squeak implements QuackBehavior {
@Override
public void quack() {
System.out.println("squeak");
}
}
//鴨子類
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public abstract void display();
public void performFly(){
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
public void setFlyBehavior(FlyBehavior flyBehavior){
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}
//具體的鴨子類
public class ModelDuck extends Duck {
public ModelDuck(){
flyBehavior = new FlyNoWay();
quackBehavior = new Quack();
}
@Override
public void display() {
System.out.println("ModelDuck");
}
}
//測試 結(jié)果
public class Test {
public static void main(String[] args) {
Duck duck = new ModelDuck();
duck.performFly();
duck.setFlyBehavior(new FlyWithWings());
duck.performFly();
}
}
上面代碼就是策略模式的內(nèi)容两踏,如果覺得十分疑惑兜喻,那就聽我慢慢道來梦染。
- 背景
某公司開發(fā)了一款十分歡迎的關(guān)于鴨子的游戲朴皆,游戲中有各種類型的鴨子,一邊游泳劃水肮疗。一邊呱呱叫扒接。有一天老板說,這個游戲太受歡迎了钾怔,我們要加入新的元素,要加入會飛的鴨子愚臀。兩天搞定7!男旗!
于是這個任務(wù)被排到了小明身上。 - 實現(xiàn)構(gòu)想
其實小明拿到拍著胸脯的說到捧毛,兩天的時間太輕松了让网,于是他開始風(fēng)風(fēng)火火的做了起來。小明寫了一個Duck類溃睹,讓所有鴨子都繼承這一個類,用來保證得到的鴨子的行為一致性,不會出現(xiàn)玩家想要一個鴨子,這邊卻畫出來一只鸚鵡左刽。然后在Duck類里面實現(xiàn)了一個fly()方法,這樣也就成功的給子類鴨子加上了fly的飛行方法。但是這樣做會導(dǎo)致所有的鴨子都具有飛行茶没。所以這個做法被否決了。
后來小明冥思苦想喂急,解決了這個問題笛求,他在Duck類里面把fly()方法 定義成抽象的,Duck的子類都需要自己實現(xiàn)這個方法探入,如果不會飛的鴨子就把fly()方法實現(xiàn)為不會飛,如果會飛的鴨子就把fly()是實現(xiàn)為會飛步氏,這樣會導(dǎo)致每種類型的鴨子必須實現(xiàn)fly()方法徒爹,如果鴨子種類太多,但就兩種類型隆嗅,會飛和不會飛。就會導(dǎo)致代碼里面寫了十多次的fly()方法的實現(xiàn)泡躯。 - 策略模式
正巧這個實現(xiàn)被路過的主席大神看到了,和小明巴拉巴拉說了一通较剃,小明頓感敬佩之情如同滔滔江水,絡(luò)繹不絕惰拱。而主席大神所說的便是上面的代碼啊送,也就是 策略模式。
代碼分析
- 分開變化和不會變化的部分
首先肯定要有Duck類馋没,用來定義一些鴨子其他的屬性,比如 腿和嘴的個數(shù)等勾怒。而會變化只有一個fly()款票。那就要把fly 和 duck 分離開來。代碼里是定義了一個接口FlyBehavior 艾少,然后FlyBehavior 和FlyWithWings實現(xiàn)了它 。先解釋一些為什么要如此做幔妨,因為我們應(yīng)該面向接口編程谍椅,而不是面向?qū)ο缶幊獭?/li>
//片段一
Dog d = new Dog();
d.bark();
//片段二
Animal animal = new Dog();
animal.makeSound;
//片段三
a = getAnimal();
a.makeSound();
通過上面三個片段,讀者可以自己理解一些面向接口的含義锁施,第一個直接new Dog(); 第二個用到了接口杖们,第三個才是最好的實現(xiàn)悉抵,它表述的含義為摘完,外面并不知道getAnimal()里面是如何實現(xiàn)的,或者說他獲得的是什么列粪。外面唯一知道的是getAnimal獲得的動物會叫。所以可以調(diào)用makeSound()方法岂座,會叫的動物很多,包括鸚鵡吃媒,鴨子吕喘,狗刑桑。
而在大神的代碼里面向接口體現(xiàn)在 Duck類里面的performFly()方法里面的flyBehaviro.fly()。
- 實現(xiàn)鴨子的行為
定義了FlyBehavior接口祠斧,F(xiàn)lyNoWay和FlyWithWings 實現(xiàn)了它。
對于不同的鴨子我們可以給飛行這個行為做不同的實現(xiàn)辕漂,而在真實的ModelDuck 鴨子類初始化過程中賦一個值即可吴超。或者也通過 setFlyBehavior()方法改變鴨子行為跋涣。
對于多用組合鸟悴,少用繼承的理解,
組合在上面代碼指的是细诸,Duck這個抽象類里面包括FlyBehavior 和QuackBehavior這兩個接口,這表明fly和quack這兩個行為是通過組合來實現(xiàn)的利赋,即一個Duck類擁有兩個屬性,而不是通過繼承獲得的
測試執(zhí)行的結(jié)果為
I can't fly
I'm flying
上面說的不是很詳細(xì)屏歹,因為有些東西并不需要講解。理解東西的話蝙眶,沒有比看代碼更好的途徑了
遲來的需求
- 小明該如何做褪那?
要有的鴨子會叫式塌,有的鴨子不會叫。這樣該如何實現(xiàn)那偏窝?
上面代碼已經(jīng)實現(xiàn)好了武学,可以略作參考。