Java設計模式之裝飾模式趣談

2016-03-30    分類:JAVA開發、程式設計開發、設計模式、首頁精華3人評論發表於2016-03-30

本文由碼農網 – 魯阿皓原創,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃

前情提要:http://blog.csdn.net/baidu_30889437/article/details/50917814<wbr><wbr><wbr><wbr>

JVM:”上次給我招的工人不錯啊!”

oo程式設計師:”………..”

JVM:”現在來我開的博物館生意越來越好了,原來”舞臺劇”的方式已經不能滿足顧客的需求了”

oo程式設計師:”………..”

JVM:”我決定要換一種運營模式,把每個演播廳都租出去,讓那些想表演節目的物件們來租演播廳和相關器械,這樣我就能坐地收錢了!”

oo程式設計師:”………..”

JVM:”合夥幹吧?怎麼樣?你三我七!”

oo程式設計師:”………..”

JVM:”四六?”

oo程式設計師:”成交!先說說需求。”

JVM:”首先有不同型別的演播廳和不同的裝飾品/器械,每種物品都要付一定的租金,你要做的就是一件事,把總租金(演播廳+飾品/器械)算出來。”

oo程式設計師:”把價格表給我!”

卡通演播廳(CartoonStudio)     100

小丑演播廳(JokerStudio) 150

超級演播廳(SuperStudio) 300

氣球(Balloon)                 10

燈光(Lamplight) 25

麥克風(Microphone) 20

最後還寫下了這個:

public abstract class Anything_ex()
{
   String description=" ";
   public String getDescription()
   {
      return description;
   }
   public abstract int cost();
}

仔細一想也對,無論是演播廳還是裝飾品,都需要描述(description)和cost(價格),寫一個共同的父類無可厚非。

接著寫下你設計的第一個類:

class CartoonandBalloon extends Anything_ex
{
   ....
   public int cost()
   {
      return 100+10;
   }
}   //帶氣球的卡通演播廳

第二個:

class CartoonandLamplight extends Anything_ex
{
   ...
   public int cost()
   {
      return 100+25;
   }
}  //帶燈光的卡通演播廳

第三個:
。。。。。

沒有第三個了!這樣寫下去可是無窮無盡的!沒辦法,換個思路。

在演播廳裡,無論什麼裝飾品都有可能出現,可以把演播廳+飾品看成一個整體,通過飾品相應的has和set來控制飾品,這樣的話,設計出來的類如下:

class CartoonStudio extends Anything_ex
{
	private  boolean Balloon=false;
	.... //省略其他變數,這裡只以氣球為例
	public boolean hasBalloon()
	{
		return Ballon;
	}
	public void setBallon()
	{
		Balloon=true;
	}
	.......//省略其他has/set方法
	public int cost()
	{
		int cost=100; //卡通演播廳的初始價格為100
		if(hasBalloon)
		{
			cost+=10;
		}
		else if(hasXXX).....//省略類推下來的程式碼

		return cost;
	}

}

這個看起來好多了,不用寫大爆炸數量的類,雖然類寫起來又臭(無數的has/set)又長(的確很長)。。。。。

但是有沒有更好的方案?

答案當然是有的,不過我們必須先明確一下,上述設計的缺點。

  • 1.臭
  • 2.長
  • 3.當飾品的租金改變的時候,必須修改所有演播廳的程式碼(cost部分),我們當然不想這樣,我們想盡可能的少修改程式碼(鬆耦合)。
  • 4.沒有面對超類/介面程式設計。
  • 5.沒有將變化的部分獨立開。
  • 6.組合可能是更好的解決方案。

下面讓我們看看。裝飾者模式是如何解決上面問題的。

裝飾者模式:動態的將責任加到物件上,若要擴充套件功能,裝飾者提供了比繼承更有彈性的替代方案。

首先,我們先將演播廳和他的裝飾者們分開,讓裝飾者繼承另一個類:

public abstract class Decorater_ex extends Anyting_ex
{
      public abstract String getDescription();
}

讓裝飾者子類重新實現getDescription()即可。

現在我們的思路是:用裝飾者裝飾演播廳,例如,一個帶麥克風和氣球的卡通演播廳,就先讓氣球裝飾卡通演播廳,再讓麥克風裝飾“帶氣球的卡通演播廳”

先讓我們分別實現這3個類:

卡通演播廳:

class CortoonStudio extends Anything_ex
{
	public CortoonStudio()
	{
		description="CortonStudio";
	}
	publuc int cost()
	{
		return 100;
	}
}

麥克風:

class Microphone extends Decorater_ex
{
	private Anything_ex studio;
	public Microphone(Anything_ex studio )
	{
		this.studio=studio;
	}
	public String getDescription()
	{
		return studio.getDescription()+",Microphone";
	}
	public int cost()
	{
		return studio.cost()+20;
	}
}

氣球:

class Balloon extends Decorater_ex
{
	private Anything_ex studio;
	public Balloon(Anything_ex studio )
	{
		this.studio=studio;
	}
	public String getDescription()
	{
		return studio.getDescription()+",Balloon";
	}
	public int cost()
	{
		return studio.cost()+10 ;
	}
}

程式碼:

Anything_ex CortoonStudio =new CortoonStudio();    //一個卡通演播廳物件
CortoonStudio=new Microphone(CortoonStudio); //拿麥克風裝飾
CortoonStudio=new Balloon(CortoonStudio);  //拿氣球裝飾
System.out.println(CortoonStudio.getDescription()+"="+CortoonStudio.cost());

輸出結果:

CortonStudio,Microphone,Balloon=130

結果是正確的。

這樣寫很好的解決了上面的問題。

  • 1.運用組合進行擴充套件,使當價格改變的時候,只需要修改本身的程式碼。
  • 2.面對超類/介面程式設計,使飾品增加種類的時候,並不需要修改被裝飾者的程式碼。
  • 3.開放——關閉原則 :程式碼應該對擴充套件開放,對修改關閉。

缺陷:

  • 1.子類繁多,影響理解程式碼(java I/O就是裝飾者模式哦。。。)。
  • 2.無法應用於需要具體類的場景。

這篇文章到此差不多結束了,作者功力尚淺,文章如有不正之處請讀者指出,海涵。

本文連結:http://www.codeceo.com/article/java-decorator-pattern.html
本文作者:碼農網 – 魯阿皓
原創作品,轉載必須在正文中標註並保留原文連結和作者等資訊。]

相關文章