最近在看設(shè)計模式,就將自己看的一些心得寫下來,做學(xué)習(xí)筆記。該篇看的是head first 設(shè)計模式的一些體會和總結(jié)。
策略模式
定義算法族,分別封裝起來,讓它們之間可以相互替換,使算法的變化獨立于使用算法的客戶。
這定義好像很晦澀難懂呀,簡單點說,就是將行為變化部分分別封裝成接口,然后使用組合接口的方式來實現(xiàn)一個對象的全部行為。(在下面的例子看我之后再回頭看定義,我想你會明白的)
設(shè)計原則(一):找出應(yīng)用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起。
其實就是把變化的部分封裝起來,不要讓其他不變的部分受到影響
設(shè)計原則(二):針對接口編程,而不是針對實現(xiàn)編程
針對接口編程的本質(zhì)是:針對超類型(super)編程
書中對這個原則有詳細(xì)的解釋(感覺這段解釋很好):這里所謂的“接口”有多個含義,接口是一個“概念”,也是一直java的interface構(gòu)造。利用多態(tài),程序可以針對超類型編程,執(zhí)行時會根據(jù)實際狀況執(zhí)行到真正的行為,不會綁死在超類型的行為上。“針對超類型編程”這句話,可以更明確的說成“變量的聲明類型應(yīng)該是超類型,通常是一個抽象類或者是一個接口”,如此,只要是具體實現(xiàn)此超類型的類所產(chǎn)生的對象,都可以指定給這個變量。這也意味著,聲明類時不用理會以后執(zhí)行時的真正對象類型!
下面是簡單多態(tài)的例子:
a.針對“實現(xiàn)編程”
聲明變量“d”為Dog類型(Animal的具體實現(xiàn)),會造成我們必須針對具體實現(xiàn)編程。
Dog d = new Dog;
d.bark();
b.但是針對“接口/超類型編程”的做法如下(正確做法):
我們知道對象是狗,但是現(xiàn)在利用annimal進行多態(tài)調(diào)用。
Animal animal = new Dog();
animal.makeSound();
設(shè)計原則(三):多用組合,少用繼承
本質(zhì)就是:通過多個接口(interface),將行為分類(比如鴨子叫和飛屬于2個不同的屬性),并實現(xiàn)該接口。這里所說的組合就是不使用繼承來實現(xiàn)鴨子的叫和飛屬性,而是通過定義接口。然后通過接口將這兩個行為組合成鴨子的屬性(叫和飛)。
在head first 里面是通過定義FlyBehavior 和 QuckBehavior.每個鴨子都有一個FlyBehavior 和 QuckBehavior,好將飛行和呱呱叫委托給他們代為處理。
代碼示例(源自head first 設(shè)計模式)
/**
* 鴨子抽象超類
* Created by nana on 2017/11/5.
*/
public abstract class Duck {
public FlyBehavior flyBehavior;//這里聲明接口類型的引用變量
public QuackBehavior quackBehavior;
public Duck(){
}
public abstract void display();
public void performFly(){
flyBehavior.fly();//委托給飛行行為類
}
public void performQuck(){
quackBehavior.quack();//委托給呱呱叫行為類
}
//游泳方法是所有鴨子都能實現(xiàn)的行為(且表現(xiàn)相同)
public void swim(){
Log.i("nana","All duck float,even decoys");
}
public void setFlyBehavior(FlyBehavior flyBehavior){
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior){
this.quackBehavior = quackBehavior;
}
}
鴨子有2個屬性(飛行和呱呱叫)下面是2個屬性定義接口
/**
* 飛行行為接口
* Created by nana on 2017/11/5.
*/
public interface FlyBehavior {
void fly();
}
/**
* 叫聲接口
* Created by nana on 2017/11/5.
*/
public interface QuackBehavior {
void quack();
}
FlyNoWay 和 FlyWithWings 是對飛行接口 FlyBehavior 的具體實現(xiàn)
/**
* 不會飛的鴨子的飛行行為實現(xiàn)類
*/
public class FlyNoWay implements FlyBehavior {
@Override
public void fly() {
Log.i("nana","FlyNoWay!!!");}
}
/**
* 鴨子用翅膀飛行的飛行實現(xiàn)類
*/
public class FlyWithWings implements FlyBehavior{
@Override
public void fly() {
Log.i("nana","FlyWithWings!!!");
}
}
Quck是對鴨子叫行為的具體實現(xiàn)
public class Quck implements QuackBehavior{
@Override
public void quack() {
Log.i("nana","quack!!!");
}
}
這個MallardDuck是鴨子抽象超類的子類實現(xiàn)
public class MallardDuck extends Duck{
public MallardDuck(){
quackBehavior = new Quck();
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
Log.i("nana","I am a Mallard duck ~~~~~");
}
}
測試類:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Duck mallard = new MallardDuck();//這里針對接口編程,多態(tài)
mallard.performFly();
mallard.setFlyBehavior(new FlyWithWings());
mallard.performFly();
mallard.performQuck();
mallard.display();
mallard.swim();
}
}
看完代碼,我們再來總結(jié)一下。使用原則一,將鴨子的行為呱呱叫和飛行行為分離出來。使用原則二和原則三,我們針對超類型編程,鴨子有抽象超類(且超類里持有飛行和叫的引用,并在超類里面使用這個應(yīng)用進行行為的處理),那么子類鴨子就可以繼承超類實現(xiàn)飛行和叫的行為。且可以根據(jù)自己實際情況選擇會飛或者用翅膀飛的飛行行為,叫的行為也可以有多個,這里沒有具體寫。
不知道你理解了嗎?看一下UML圖可能更直觀。
上述圖片是應(yīng)用網(wǎng)友的博客中圖片,發(fā)現(xiàn)該網(wǎng)友對書中例子更全面。可以參考鏈接:https://www.cnblogs.com/wolf-sun/p/3534573.html
以上是讀書筆記,如果有問題。歡迎交流。