JAVA 設計模式 --- 裝飾者模式

裝飾者模式 (Decorator)java

動態地給一個對象添加一些額外的職責。是一種結構式模式,就增長功能來講,Decorator 模式相比生成子類更爲靈活。換言之,客戶端並不會以爲對象在裝飾前和裝飾後有什麼不一樣。裝飾模式能夠在不使用創造更多子類的狀況下,將對象的功能加以擴展。設計模式

要點: 裝飾者與被裝飾者擁有共同的超類,繼承的目的是繼承類型,而不是行爲.ide

裝飾模式的類圖以下:性能

在裝飾模式中的角色有:測試

  ●  抽象構件(Component)角色:給出一個抽象接口,以規範準備接收附加責任的對象。this

  ●  具體構件(ConcreteComponent)角色:定義一個將要接收附加責任的類。設計

  ●  裝飾(Decorator)角色:持有一個構件(Component)對象的實例,並定義一個與抽象構件接口一致的接口。code

  ●  具體裝飾(ConcreteDecorator)角色:負責給構件對象「貼上」附加的責任。component

代碼說明:對象

抽象構件角色:

public interface Component{
    public void sampleOperation();
}

具體掛件角色:

public class ConcreteComponent implements Component{
    @Override
    public void sampleOperation() {
        System.out.println("初始行爲");
    }
}

裝飾角色:

public class Decorator implements Component{

	private Component component;
	
	public Decorator(Component component){
		this.component = component;
	}
	
	@Override
	public void sampleOperation() {
		// 委派給 構件
		component.sampleOperation();
	}

}

具體裝飾角色

public class ConcreteDecoratorA extends Decorator{

	public ConcreteDecoratorA(Component component) {
		super(component);
	}
	
	@Override
	public void sampleOperation() {
		super.sampleOperation();
		// 其餘 可擴展的行爲
	}

}

實例說明(齊天大聖的例子):

  孫悟空有七十二般變化,他的每一種變化都給他帶來一種附加的本領。他變成魚兒時,就能夠到水裏游泳;他變成鳥兒時,就能夠在天上飛行。

  本例中,Component 的角色便由鼎鼎大名的齊天大聖扮演;ConcreteComponent 的角色屬於大聖的本尊,就是猢猻本人;Decorator 的角色由大聖的七十二變扮演。而 ConcreteDecorator 的角色即是魚兒、鳥兒等七十二般變化。

抽象構件角色: 大聖的稱號

public interface TheGreatestSage {

	  public void move();
	
}

具體構件角色  :「大聖本尊」猢猻類

public class Monkey implements TheGreatestSage{

	@Override
	public void move() {
		System.out.println("Monkey Move");
	}

}

抽象 裝飾者 角色: 「七十二變」

public class Change implements TheGreatestSage{

	private TheGreatestSage sage;
	
	public Change(TheGreatestSage sage){
		this.sage = sage;
	}
	
	@Override
	public void move() {
		sage.move();
	}
}

 具體裝飾角色 :「魚兒」

public class Fish extends Change{

	public Fish(TheGreatestSage sage) {
		super(sage);
	}
	
	@Override
	public void move() {
		 System.out.println("Fish Move");
		 System.out.println("Fish 的 其餘行爲動做描述");
	}

}

 具體裝飾角色 :「小鳥」

public class Bird extends Change{

	public Bird(TheGreatestSage sage) {
		super(sage);
	}
	
	@Override
	public void move() {
		 System.out.println("Bird Move");
		 System.out.println("Bird 的 其餘行爲動做描述");
	}

}

測試:

public class Client {

	public static void main(String[] args) {
		TheGreatestSage sage = new Monkey();

		Fish fish = new Fish(sage);
		fish.move();
		
		Bird bird = new Bird(fish);
		bird.move();
	}
	
}

上面的例子中,系統把大聖從一隻猢猻裝飾成了一隻鳥兒(把鳥兒的功能加到了猢猻身上),而後又把鳥兒裝飾成了一條魚兒(把魚兒的功能加到了猢猻+鳥兒身上,獲得了猢猻+鳥兒+魚兒)。

裝飾模式的簡化

大多數狀況下,裝飾模式的實現都要比上面給出的示意性例子要簡單。

若是隻有一個ConcreteComponent類,那麼能夠考慮去掉抽象的Component類(接口),把Decorator做爲一個ConcreteComponent子類。以下圖所示:

若是隻有一個ConcreteDecorator類,那麼就沒有必要創建一個單獨的Decorator類,而能夠把Decorator和ConcreteDecorator的責任合併成一個類。甚至在只有兩個ConcreteDecorator類的狀況下,均可以這樣作。以下圖所示:

半透明的 裝飾模式

  然而,純粹的裝飾模式很難找到。裝飾模式的用意是在不改變接口的前提下,加強所考慮的類的性能。在加強性能的時候,每每須要創建新的公開的方法。即使是在孫大聖的系統裏,也須要新的方法。好比齊天大聖類並無飛行的能力,而鳥兒有。這就意味着鳥兒應當有一個新的fly()方法。再好比,齊天大聖類並無游泳的能力,而魚兒有,這就意味着在魚兒類裏應當有一個新的swim()方法。

  這就致使了大多數的裝飾模式的實現都是「半透明」的,而不是徹底透明的。換言之,容許裝飾模式改變接口,增長新的方法。這意味着客戶端能夠聲明ConcreteDecorator類型的變量,從而能夠調用ConcreteDecorator類中才有的方法:

TheGreatestSage sage = new Monkey();
Bird bird = new Bird(sage);
bird.fly();

     半透明的裝飾模式是介於裝飾模式和適配器模式之間的。適配器模式的用意是改變所考慮的類的接口,也能夠經過改寫一個或幾個方法,或增長新的方法來加強或改變所考慮的類的功能。大多數的裝飾模式其實是半透明的裝飾模式,這樣的裝飾模式也稱作半裝飾、半適配器模式。

裝飾模式的優勢

(1)裝飾模式與繼承關係的目的都是要擴展對象的功能,可是裝飾模式能夠提供比繼承更多的靈活性。裝飾模式容許系統動態決定「貼上」一個須要的「裝飾」,或者除掉一個不須要的「裝飾」。繼承關係則不一樣,繼承關係是靜態的,它在系統運行前就決定了。

(2)經過使用不一樣的具體裝飾類以及這些裝飾類的排列組合,設計師能夠創造出不少不一樣行爲的組合。

裝飾模式的缺點:

     因爲使用裝飾模式,能夠比使用繼承關係須要較少數目的類。使用較少的類,固然使設計比較易於進行。可是,在另外一方面,使用裝飾模式會產生比使用繼承關係更多的對象。更多的對象會使得查錯變得困難,特別是這些對象看上去都很相像。

-------------------------------------------------------------------------------------------------------------------------------------------------------

設計模式在JAVA I/O庫中的應用

裝飾模式在Java語言中的最著名的應用莫過於Java I/O標準庫的設計了。

Java I/O庫的對象結構圖以下,因爲Java I/O的對象衆多,所以只畫出InputStream的部分。

 根據上圖能夠看出:

  ●  抽象構件(Component)角色:由InputStream扮演。這是一個抽象類,爲各類子類型提供統一的接口。

  ●  具體構件(ConcreteComponent)角色:由ByteArrayInputStream、FileInputStream、PipedInputStream、StringBufferInputStream等類扮演。它們實現了抽象構件角色所規定的接口。

  ●  抽象裝飾(Decorator)角色:由FilterInputStream扮演。它實現了InputStream所規定的接口。

  ●  具體裝飾(ConcreteDecorator)角色:由幾個類扮演,分別是BufferedInputStream、DataInputStream以及兩個不經常使用到的類LineNumberInputStream、PushbackInputStream。

例如:

public class IOTest {

    public static void main(String[] args) throws IOException {
        // 流式讀取文件
        DataInputStream dis = null;
        try{
            dis = new DataInputStream(
                    new BufferedInputStream(
                            new FileInputStream("test.txt")
                    )
            );
            //讀取文件內容
            byte[] bs = new byte[dis.available()];
            dis.read(bs);
            String content = new String(bs);
            System.out.println(content);
        }finally{
            dis.close();
        }
    }
}

     觀察上面的代碼,會發現最裏層是一個FileInputStream對象,而後把它傳遞給一個BufferedInputStream對象,通過BufferedInputStream處理,再把處理後的對象傳遞給了DataInputStream對象進行處理,這個過程其實就是裝飾器的組裝過程,FileInputStream對象至關於原始的被裝飾的對象,而BufferedInputStream對象和DataInputStream對象則至關於裝飾器。

相關文章
相關標籤/搜索