瞭解裝飾模式:
我們來看一下“裝飾”是什麼意思:
(截圖來自百度漢語)
就這個詞,已經快解釋清楚“裝飾模式”是什麼東西了。
裝飾模式:動態的將新功能附加到對象上。
怎麼去動態添加?
其實是通過套娃實現的。
而且,沒有什麼附加功能是套娃解決不了的,如果不行,那就套兩層。
我就,模擬養成養魔法魚,做例子來講一下。
裝飾模式小案例:
首先咱們建個魚的父類。
這是類的作用相當於管道,把主體類和各個裝飾類鏈接起來。
package 裝飾者模式;
public abstract class AboutFish {
public AboutFish obj;
public String des;
private float price = 0.0f;
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
/**
* 計算費用的抽象方法,子類實現
* @return
*/
public abstract float cost();
}
然後寫魔法魚類
這個類是主體類,所有的裝飾都是給他用的。
package 裝飾者模式;
public class Fish extends AboutFish {
public Fish() {
setDes("魔法魚魚卵");
setPrice(10.0f);
}
@Override
public float cost() {
return super.getPrice();
}
}
到現在,還沒有用到裝飾。
我們直接開始模擬養成魔法魚。在過程中使用、講述裝飾模式。
package 裝飾者模式;
public class Me {
public static void main(String[] args) {
// 購買魚卵
AboutFish fish = new Fish();
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已獲得“魔法魚魚卵 X1”,有“水”就可以孵化魚卵了,快去尋找“水”吧!");
System.out.println("-----");
}
}
運行結果:
已經花了:10.0
魔法魚魚卵
已獲得“魔法魚魚卵 X1”,有“水”就可以孵化魚卵了,快去尋找“水”吧!
-----
我們開始找水吧!(準備好,開始套娃了)
首先寫個裝飾抽象類(所有抽象類的父類),接上管道(繼承魚的父類)
package 裝飾者模式;
public class Decorator extends AboutFish{
public Decorator(AboutFish obj) {
this.obj=obj;
}
@Override
public float cost() {
return super.getPrice()+obj.cost();
}
@Override
public String getDes() {
return obj.getDes();
}
}
然後寫水類(裝飾類)
package 裝飾者模式;
public class Water extends Decorator{
public Water(AboutFish obj) {
super(obj);
setDes("水");
setPrice(0.0f);
}
}
開始孵化吧!
package 裝飾者模式;
public class Me {
public static void main(String[] args) {
// 購買魚卵
AboutFish fish = new Fish();
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已獲得“魔法魚魚卵 X1”,有“水”就可以孵化魚卵了,快去尋找“水”吧!");
System.out.println("-----");
// 獲得水
fish = new Water(fish);
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已獲得“水”,請儘快孵化吧");
System.out.println("-----");
System.out.println("開始孵化...");
fish.obj.des="小魚苗";
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("孵化成功,趕快給小魚苗找點喫的吧!");
}
}
運行結果:
已經花了:10.0
魔法魚魚卵
已獲得“魔法魚魚卵 X1”,有“水”就可以孵化魚卵了,快去尋找“水”吧!
-----
已經花了:10.0
魔法魚魚卵
已獲得“水”,請儘快孵化吧
-----
開始孵化...
已經花了:10.0
小魚苗
孵化成功,趕快給小魚苗找點喫的吧!
到此我們已經裝飾了一次了。
繼續給小魚苗尋找食物吧(裝飾類、又套一層娃)。
package 裝飾者模式;
public class 脫殼豐年蝦卵__小魚苗食物 extends Decorator{
public 脫殼豐年蝦卵__小魚苗食物(AboutFish obj) {
super(obj);
setDes("脫殼豐年蝦卵");
setPrice(5.0f);
}
}
開始餵食吧。
package 裝飾者模式;
public class Me {
public static void main(String[] args) {
// 購買魚卵
AboutFish fish = new Fish();
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已獲得“魔法魚魚卵 X1”,有“水”就可以孵化魚卵了,快去尋找“水”吧!");
System.out.println("-----");
// 獲得水
fish = new Water(fish);
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已獲得“水”,請儘快孵化吧");
System.out.println("-----");
System.out.println("開始孵化...");
fish.obj.des="小魚苗";
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("孵化成功,趕快給小魚苗找點喫的吧!");
// 獲得脫殼豐年蝦卵
fish = new 脫殼豐年蝦卵__小魚苗食物(fish);
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已獲得“脫殼豐年蝦卵”,請餵食小魚苗,讓它快快長大吧");
System.out.println("-----");
System.out.println("開始餵食..");
fish.obj.obj.des="幼魚";
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println(".脫離幼苗期,成爲幼魚,幼魚得喫水蚤!");
}
}
運行結果:
已經花了:10.0
魔法魚魚卵
已獲得“魔法魚魚卵 X1”,有“水”就可以孵化魚卵了,快去尋找“水”吧!
-----
已經花了:10.0
魔法魚魚卵
已獲得“水”,請儘快孵化吧
-----
開始孵化...
已經花了:10.0
小魚苗
孵化成功,趕快給小魚苗找點喫的吧!
已經花了:15.0
小魚苗
已獲得“脫殼豐年蝦卵”,請餵食小魚苗,讓它快快長大吧
-----
開始餵食..
已經花了:15.0
幼魚
.脫離幼苗期,成爲幼魚,幼魚得喫水蚤!
裝飾兩次了。
找水蚤吧(裝飾類、雙套一層娃)。
package 裝飾者模式;
public class 水蚤__幼魚食物 extends Decorator{
public 水蚤__幼魚食物(AboutFish obj) {
super(obj);
setDes("水蚤");
setPrice(10.0f);
}
}
開始餵魚:
package 裝飾者模式;
public class Me {
public static void main(String[] args) {
// 購買魚卵
AboutFish fish = new Fish();
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已獲得“魔法魚魚卵 X1”,有“水”就可以孵化魚卵了,快去尋找“水”吧!");
System.out.println("-----");
// 獲得水
fish = new Water(fish);
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已獲得“水”,請儘快孵化吧");
System.out.println("-----");
System.out.println("開始孵化...");
fish.obj.des="小魚苗";
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("孵化成功,趕快給小魚苗找點喫的吧!");
// 獲得脫殼豐年蝦卵
fish = new 脫殼豐年蝦卵__小魚苗食物(fish);
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已獲得“脫殼豐年蝦卵”,請餵食小魚苗,讓它快快長大吧");
System.out.println("-----");
System.out.println("開始餵食..");
fish.obj.obj.des="幼魚";
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println(".脫離幼苗期,成爲幼魚,幼魚得喫水蚤!");
// 獲得水蚤
fish = new 水蚤__幼魚食物(fish);
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
System.out.println("已獲得“水蚤”,請餵食幼魚,讓它快快長大吧");
System.out.println("-----");
System.out.println("開始餵食...脫離幼魚期,成爲成魚");
fish.obj.obj.obj.des="成魚";
System.out.println("已經花了:"+fish.cost());
System.out.println(fish.getDes());
}
}
運行結果:
已經花了:10.0
魔法魚魚卵
已獲得“魔法魚魚卵 X1”,有“水”就可以孵化魚卵了,快去尋找“水”吧!
-----
已經花了:10.0
魔法魚魚卵
已獲得“水”,請儘快孵化吧
-----
開始孵化...
已經花了:10.0
小魚苗
孵化成功,趕快給小魚苗找點喫的吧!
已經花了:15.0
小魚苗
已獲得“脫殼豐年蝦卵”,請餵食小魚苗,讓它快快長大吧
-----
開始餵食..
已經花了:15.0
幼魚
.脫離幼苗期,成爲幼魚,幼魚得喫水蚤!
已經花了:25.0
幼魚
已獲得“水蚤”,請餵食幼魚,讓它快快長大吧
-----
開始餵食...脫離幼魚期,成爲成魚
已經花了:25.0
成魚
接下來還有性成熟、交尾、產卵、衰老、死亡,等等。
你可以接着又、雙繼續叒、叕的套下去
今天咱們的娃,就先套到這裏,啊不對,咱們的魚,就先養到這裏吧。
畢竟它是一條工具魚。養到這裏,就夠我們理解裝飾模式了。
原理解析:
這是原理圖:
(關於向上轉型,不瞭解的可以看我的另一篇博客學習:Java知識掃盲——向上轉型(類向上轉型、接口向上轉型)以及向上轉型的優勢、靈活運用)
這是串起來以後的效果圖:
通過這種無限套娃,讓本來的Fish可以經過多次修飾,動態的添加功能。
到現在,我想大家已經理解什麼是裝飾模式了。
裝飾模式的優點:
如大家所見,擴展性非常好,只要套下去就可以了。。。