裝飾者模式是在沒必要改變原類文件和使用繼承的狀況下,動態地擴展一個對象的功能。它是經過建立一個包裝對象,也就是裝飾來包裹真實的對象。java
1) 裝飾對象和真實對象有相同的接口。這樣客戶端對象就能以和真實對象相同的方式和裝飾對象交互。ide
2) 裝飾對象包含一個真實對象的引用。this
3) 裝飾對象接受全部來自客戶端的請求,它把這些請求轉發給真實的對象。spa
4) 裝飾對象能夠在轉發這些請求之前或之後增長一些附加功能。這樣就確保了在運行時,不用修改給定對象的結構就能夠在外部增長附加的功能。在面向對象的設計中,一般是經過繼承來實現對給定類的功能擴展。設計
1) 須要擴展一個類的功能,或給一個類添加附加職責。代理
2) 須要動態的給一個對象添加功能,這些功能能夠再動態的撤銷。code
3) 須要增長由一些基本功能的排列組合而產生的很是大量的功能,從而使繼承關係變的不現實。對象
4) 當不能採用生成子類的方法進行擴充時。一種狀況是,可能有大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增加。另外一種狀況多是由於類定義被隱藏,或類定義不能用於生成子類。繼承
需求:接口
模擬人穿衣服
public class Demo1 { public static void main(String[] args) { Person person = new Person(); person.setName("二哈"); person.wearTshirt(); person.wearJeans(); person.wearShoes(); } } class Person { private String name; public void wearTshirt() { System.out.println(name + "穿了一件T恤"); } public void wearSweater() { System.out.println(name + "穿了一件毛衣"); } public void wearJeans() { System.out.println(name + "穿了一條褲子"); } public void wearShoes() { System.out.println(name + "穿了一雙鞋"); } // public ..... -- 違反開放-封閉原則 public String getName() { return name; } public void setName(String name) { this.name = name; } }
能夠看到,若是要增長新的衣服,就須要擴展方法,這就違背了「開放-封閉原則」。
public class Demo2 { public static void main(String[] args) { Person person = new Person(); Clothes Tshirt = new TShirt(); Clothes shoes = new Shoes(); Clothes superman = new SupermanClothes(); person.wear(superman); person.wear(Tshirt); person.wear(shoes); } } class Person { private String name; public void wear(Clothes clothes) { System.out.println(name + "穿了" + clothes.getName()); } public String getName() { return name; } public void setName(String name) { this.name = name; } } abstract class Clothes { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } class TShirt extends Clothes { } class Shoes extends Clothes { } class SupermanClothes extends Clothes { }
這樣確實達到效果了,但每次穿衣服的時候總感受是當着衆人的面穿,並且邏輯也不對:每次都是人在穿,但實際狀況是:穿了一件後,下一件衣服是套在原來那件衣服上!須要改進!
public class Demo3 { public static void main(String[] args) { Person person = new Person(); person.setName("二狗"); Clothes tshirt = new Tshirt(); person.wear(tshirt); Clothes coat = new Coat(); tshirt.wear(coat); coat.show(); } } class Person { private String name; public void show() { System.out.println(name); } public void wear(Clothes clothes) { clothes.setWornClothes(this); } public String getName() { return name; } public void setName(String name) { this.name = name; } } abstract class Clothes extends Person { private Person wornClothes; //要被穿的衣服/人 private String clothesName; @Override public void show() { System.out.println(clothesName + "\t"); wornClothes.show(); } public String getClothesName() { return clothesName; } public void setClothesName(String clothesName) { this.clothesName = clothesName; } public Person getWornClothes() { return wornClothes; } public void setWornClothes(Person wornClothes) { this.wornClothes = wornClothes; } } class Tshirt extends Clothes { public Tshirt () { this.setClothesName("T恤"); } } class Coat extends Clothes { public Coat() { this.setClothesName("大衣"); } } class Jeans extends Clothes { public Jeans() { this.setClothesName("褲子"); } }
需求:
a) 擴展BufferedReader類,使其每次讀取文本信息時能夠在文本前打印行號
b) 擴展BufferedReader類,使其每次讀取文本信息時能夠在文本後打印省略號
c) 擴展BufferedReader類,使其每次讀取文本信息時能夠在文本前和文本後打印引號
import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; public class Demo1 { public static void main(String[] args) throws Exception { BufferedReader br = new ReaderLineNumAndSusp(new InputStreamReader(new FileInputStream("D:/test.txt"), "GBK")); String readline = null; while ((readline = br.readLine()) != null) { System.out.println(readline); } br.close(); } } //需求1:加強BufferedReader類,使每次讀取的內容前面加上行號 class ReaderLineNum extends BufferedReader { private int lineNum = 1; public ReaderLineNum(Reader in) { super(in); } @Override public String readLine() throws IOException { String readline = super.readLine(); if (readline == null) { return null; } readline = lineNum + readline; lineNum++; return readline; } } //需求2:加強BufferedReader類,使每次讀取的內容後面加上省略號 class ReaderSusp extends BufferedReader { public ReaderSusp(Reader in) { super(in); } @Override public String readLine() throws IOException { String readline = super.readLine(); if (readline == null) { return null; } readline = readline + "……"; return readline; } } //需求3:加強BufferedReader類,使每次讀取的內容先後加上雙引號 class ReaderQuot extends BufferedReader { public ReaderQuot(Reader in) { super(in); } @Override public String readLine() throws IOException { String readline = super.readLine(); if (readline == null) { return null; } readline = "「" + readline + "」"; return readline; } } //需求4:加強BufferedReader類,使每次讀取的內容前加行號,內容後加省略號 class ReaderLineNumAndSusp extends BufferedReader { private int lineNum = 1; public ReaderLineNumAndSusp(Reader in) { super(in); } @Override public String readLine() throws IOException { String readline = super.readLine(); if (readline == null) { return null; } readline = lineNum + readline + "……"; lineNum++; return readline; } } //需求5:。。。
import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; public class Demo2 { public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D:/test.txt"), "GBK")); BufferedReader brLineNum = new ReaderLineNum(br); BufferedReader brSusp = new ReaderSusp(brLineNum); String readline = null; while ((readline = brSusp.readLine()) != null) { System.out.println(readline); } brSusp.close(); } } class ReaderLineNum extends BufferedReader { private int lineNum = 1; private BufferedReader baseReader; public ReaderLineNum(Reader in) { super(in); this.baseReader = (BufferedReader) in; } @Override public String readLine() throws IOException { String readline = baseReader.readLine(); if (readline == null) { return null; } readline = lineNum + readline; lineNum++; return readline; } } class ReaderSusp extends BufferedReader { private BufferedReader baseReader; public ReaderSusp(Reader in) { super(in); this.baseReader = (BufferedReader) in; } @Override public String readLine() throws IOException { String readline = baseReader.readLine(); if (readline == null) { return null; } return readline + "……"; } }
能夠實現三個類完成7種功能。
建造者模式須要有一套完整的建造過程和順序
裝飾者模式更隨意,靈活(哪怕內褲外穿。。。)
裝飾者模式能夠互相裝飾,而代理模式有很明確的主從關係。