設計模式——裝飾器模式
1-裝飾器模式的定義
裝飾器模式定義:動態的爲一個對象增加新的功能,用於代替繼承的技術,無須通過繼承增加子類就能擴展對象的新功能。使用對象的關聯關係代替繼承關係,更加靈活,同時避免類型體系的快速膨脹。當需要給一個已有的類的功能上新增功能時,裝飾器模式提供了一個很好的解決方案,它把每個要裝飾的功能放在單獨的類中,並讓這個類包裝它需要裝飾的對象,因此,當需要執行特殊行爲時,客戶代碼就可以在運行時根據需要有選擇地、按順序地使用裝飾功能包裝對象。
No BB,Show Code!
2-裝飾器模式的具體代碼實現
2-1定義一個接口
定義一個接口,該接口定義一個可以不斷擴展功能的方法!
package designPattern.test.decorator;
/**
* 行駛接口,有一個move()方法,可以通過裝飾器不斷增強功能
*/
public interface Driving {
void move();
}
2-2定義兩個簡單實現
簡單實現1-Bike
package designPattern.test.decorator;
/**
* 自行車行駛
*/
public class Bike implements Driving {
/**
* 初始的自行車行駛方法
*/
@Override
public void move() {
System.out.println("鏈條傳動自行車,騎着累啊!");
}
}
簡單實現2-Car
package designPattern.test.decorator;
/**
* 汽車
*/
public class Car implements Driving {
@Override
public void move() {
System.out.println("汽車行駛,速度快!");
}
}
2-3定義一個抽象裝飾類
package designPattern.test.decorator;
/**
* 抽象的裝飾類
*/
public abstract class DrivingDecorator implements Driving {
private Driving driving;
public DrivingDecorator() {
}
/**
* 被裝飾的對象作爲構造器參數傳入
*/
public DrivingDecorator(Driving driving) {
this.driving = driving;
}
public Driving getDriving() {
return driving;
}
public void setDriving(Driving driving) {
this.driving = driving;
}
/**
* 實現基礎的功能
*/
@Override
public void move() {
driving.move();
}
}
2-4定義具體的裝飾類
具體裝飾類1-FlyDecorator
package designPattern.test.decorator;
/**
* 飛行裝飾類
*/
public class FlyDecorator extends DrivingDecorator {
/**
* 被裝飾的對象唄裝飾對象所持有
*/
public FlyDecorator(Driving driving) {
super(driving);
}
/**
* 裝飾對象新增方法
*/
public void fly() {
System.out.println("飛起來了");
}
/**
* 功能增強的move方法
*/
public void move() {
super.move();
fly();
}
}
定義具體的裝飾類-WaterDecorator
package designPattern.test.decorator;
/**
* 入海行駛裝飾器
*/
public class WaterDecorator extends DrivingDecorator {
/**
* 被裝飾的對象唄裝飾對象所持有
*/
public WaterDecorator(Driving driving) {
super(driving);
}
/**
* 裝飾對象新增方法
*/
public void water() {
System.out.println("遊起來了");
}
/**
* 功能增強的move方法
*/
public void move() {
super.move();
water();
}
}
定義具體的實現類-AIDecorator
package designPattern.test.decorator;
/**
* 智能裝飾
*/
public class AIDecorator extends DrivingDecorator {
/**
* 被裝飾的對象唄裝飾對象所持有
*/
public AIDecorator(Driving driving) {
super(driving);
}
/**
* 裝飾對象新增方法
*/
public void ai() {
System.out.println("智能起來了");
}
/**
* 功能增強的move方法
*/
public void move() {
super.move();
ai();
}
}
如代碼所示,每一個具體的裝飾類都繼承了抽象的裝飾類,將被裝飾的對象作爲裝飾對象的構造器參數傳入,不斷的增強被裝飾對象的功能!不同的裝飾功能可以放在不同的類中,每個裝飾器類只需考慮自己需要增強的功能,這樣代碼看起來將更加清晰!
3-測試
測試代碼如下
package designPattern.test.decorator;
import org.junit.Test;
/**
* 裝飾器模式測試
*/
public class DecoratorTest {
@Test
public void testDecorator(){
Driving bike = new FlyDecorator(new Bike());
bike.move();
Driving bike1 = new WaterDecorator(new Bike());
bike1.move();
Driving bike2 = new AIDecorator(new Bike());
bike2.move();
Driving car = new AIDecorator(new Car());
car.move();
}
}
打印結果如下:
鏈條傳動自行車,騎着累啊!
飛起來了
鏈條傳動自行車,騎着累啊!
遊起來了
鏈條傳動自行車,騎着累啊!
智能起來了
汽車行駛,速度快!
智能起來了
總結:裝飾器模式可以在原有類的基礎功能保持不變的情況下,增加新的功能,而且可以不斷的增加新的功能,這些新增功能的使用也完全由程序員控制,每個裝飾器類單獨分開,各自新增不同的功能,代碼層次清晰易懂!
4-裝飾器模式的典型應用
裝飾器模式最典型的應用可以說是jdk中的IO系統,代碼如下:
package designPattern.test.decorator.fileDecorator;
import org.junit.Test;
import java.io.*;
/**
* io系統的裝飾器應用
*/
public class FileTest {
@Test
public void testFileInputStream() throws Exception{
long start = System.currentTimeMillis();
InputStream inputStream = new FileInputStream(new File("D:/trace.log"));
printLog(inputStream);
System.out.println("============================Time:"+(System.currentTimeMillis() - start));
}
@Test
public void testFileBuffered() throws Exception {
long start = System.currentTimeMillis();
InputStream inputStream = new BufferedInputStream(new FileInputStream(new File("D:/trace.log")));
printLog(inputStream);
System.out.println("============================Time:"+(System.currentTimeMillis() - start));
}
@Test
public void testFileDataInputStream() throws Exception {
long start = System.currentTimeMillis();
InputStream inputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(new File("D:/trace.log"))));
printLog(inputStream);
System.out.println("============================Time:"+(System.currentTimeMillis() - start));
}
private void printLog(InputStream inputStream) throws Exception{
int i = 0;
byte[] b = new byte[1024];
while ((i = inputStream.read(b)) != -1) {
String s = new String(b);
System.out.println(s);
}
}
}
代碼中,FileInputStream,BufferedInputStream,DataInputStream都是InputStream抽象類的具體實例,FileInputStream的實例可以作爲傳參傳入BufferedInputStream中,給文件IO新增緩衝區作用,類似於批量處理,提高了IO性能,同樣可以把BufferedInputStream的實例作爲傳參傳給DataInputStream的構造器中,給文件IO新增數據格式輸入的功能(存疑)!