設計模式之結構性模式(二)
設計模式之結構性模式(二)
三、橋接模式
四、組合模式
五、裝飾模式
三、橋接模式
如果用多層繼承結構實現下圖關係,有如下問題:
1)擴充套件性問題
2)違反單一職責原則
將其分為兩個維度:
型別維度和品牌維度
Computer2
/** * 電腦型別 */ package com.bridge; public class Computer2 { //品牌 protected Brand brand; public Computer2(Brand brand) { this.brand = brand; } public void sale() { brand.sale(); } } //桌上型電腦 class Desktop2 extends Computer2 { public Desktop2(Brand brand) { super(brand); } public void sale() { super.sale(); System.out.println("銷售臺式機"); } } //筆記本 class Laptop2 extends Computer2 { public Laptop2(Brand brand) { super(brand); } public void sale() { super.sale(); System.out.println("銷售筆記本"); } } //平板 class Pad2 extends Computer2 { public Pad2(Brand brand) { super(brand); } public void sale() { super.sale(); System.out.println("銷售平板"); } }
Brand
/** * 品牌型別 */ package com.bridge; public interface Brand { public void sale(); } class Lenovo implements Brand { @Override public void sale() { System.out.println("銷售聯想電腦"); } } class Dell implements Brand { @Override public void sale() { System.out.println("銷售戴爾電腦"); } }
Client
package com.bridge;
public class Client {
public static void main(String[] args) {
Computer2 c = new Desktop2(new Lenovo());
c.sale();
}
}
結果:
銷售聯想電腦
銷售臺式機
橋接模式總結:
1)可以取代多層繼承方案,多層繼承違背了單一職責原則,複用性差,類個數多;橋接模式極大減少了子類的個數,降低管理和維護成本
2)橋接模式提高了系統的可擴充套件性,在兩個變化的維度中任意變化一個維度,都不需要修改原有的系統,符合開閉原則
橋接模式應用場景:
1)JDBC驅動程式
2)AWT中的Peer架構
3)銀行日誌管理
格式分類:操作日誌、交易日誌、異常日誌
距離分類:本地記錄日誌、異地記錄日誌
4)人力資源系統中的獎金獎金計算模組
5)OA系統中的訊息處理
四、組合模式
使用場景:把部分和整體的關係用樹形結構來表示,從而使客戶端可以使用統一的方式處理部分物件和整體物件
核心:
抽象掛件(Component)角色:定義了葉子和容器構建的共同點
葉子(Leaf)構件角色:無子節點
容器(Composite)構件角色:有容器特徵,可以包含葉子節點
組合模式工作流程分析:
1)組合模式為處理樹形結構提供了完美的解決方案,描述如何將容器和葉子進行遞迴組合,使得使用者在使用時可以一致性的對待容器和葉子。
2)當容器物件的指定方法被呼叫時,將遍歷整個樹形結構,尋找也包含這個方法的成員,並執行呼叫,其中,使用了遞迴呼叫的機制對整個結構進行處理
例項:模擬防毒軟體架構設計
Conponent
/**
* 抽象元件
*/
package com.composite;
public interface Component {
public void operation();
}
//葉子元件
interface Leaf extends Component {
}
//容器元件
interface Composite extends Component {
void add(Component c);
void remove(Component c);
Composite getChild(int index);
}
AbstractFile
package com.composite;
import java.util.ArrayList;
import java.util.List;
//抽象構建
public interface AbstractFile {
void killVirus();//查毒
}
//文字檔案
class TextFile implements AbstractFile {
private String name;
public TextFile(String name) {
this.name = name;
}
@Override
public void killVirus() {
System.out.println("---文字檔案:"+this.name+",進行查殺");
}
}
//影象檔案
class ImageFile implements AbstractFile {
private String name;
public ImageFile(String name) {
this.name = name;
}
@Override
public void killVirus() {
System.out.println("---影象檔案:"+this.name+",進行查殺");
}
}
//視訊檔案
class VedioFile implements AbstractFile {
private String name;
public VedioFile(String name) {
this.name = name;
}
@Override
public void killVirus() {
System.out.println("---視訊檔案:"+this.name+",進行查殺");
}
}
//資料夾
class Folder implements AbstractFile {
private String name;
//容器
private List<AbstractFile> list = new ArrayList<AbstractFile>();
public Folder(String name) {
this.name = name;
}
//新增
public void add(AbstractFile file) {
list.add(file);
}
//移除
public void remove(AbstractFile file) {
list.remove(file);
}
//獲取
public AbstractFile getChild(int index) {
return list.get(index);
}
@Override
public void killVirus() {
System.out.println("---資料夾:"+this.name+",進行查殺");
//遍歷容器
for(AbstractFile file:list) {
file.killVirus();
}
}
}
Client
package com.composite;
public class Client {
public static void main(String[] args) {
AbstractFile f1,f2,f3;//檔案
Folder f = new Folder("我的收藏");//資料夾
Folder f11 = new Folder("我的電影");//資料夾
//檔案
f1 = new TextFile("hello.txt");
f2 = new ImageFile("111.jpg");
f3 = new VedioFile("視訊");
//將各個檔案加入到資料夾中
f.add(f1);
f.add(f2);
f11.add(f3);
f.add(f11);
//查殺資料夾
f.killVirus();
}
}
結果
---資料夾:我的收藏,進行查殺
---文字檔案:hello.txt,進行查殺
---影象檔案:111.jpg,進行查殺
---資料夾:我的電影,進行查殺
---視訊檔案:視訊,進行查殺
組合模
式應用場景:
1)作業系統的資源管理器
2)GUI中的容器層次圖
2)XML檔案解析
4)OA系統中組織結構的處理
5)Junit單元測試框架
底層設計就是典型的組合模式,TestCase(葉子)、TestUnite(容器)、Test介面(抽象)
五、裝飾模式
職責:
1)動態的為一個物件增加新的功能
2)裝飾模式是一種代替繼承的技術,無需通過繼承增加子類就能擴充套件性功能,使用物件的關聯關係代替繼承關係,更加靈活,同時避免型別體系的快速膨脹
實現細節:
1)Component抽象構件角色
真實物件和裝飾物件有相同的介面,因此客戶端物件能夠以與真實物件相同的方式同裝飾物件互動
2)ConcreteComponent具體構件角色(真實物件)
io流中的FileInputStream、FileOutputStream
3)Decorator裝飾角色
持有一個抽象構件的引用,裝飾物件接受所有客戶端的請求,並把這些請求轉發給真實的物件,因此就能在真是物件呼叫後增加新的功能
4)ConcreteDecorato具體裝飾角色
負責給構件物件增加新的責任
例項:車
實現細節:
package com.decorate;
//抽象構件角色Component
public interface Icar {
public void move();
}
//具體構件角色ConcreteComponent
class Car implements Icar {
@Override
public void move() {
System.out.println("陸地上跑");
}
}
//Decorate裝飾角色
class SuperCar implements Icar {
//protected供子類使用
protected Icar car;
public SuperCar(Icar car) {
super();
this.car = car;
}
@Override
public void move() {
car.move();
}
}
//具體裝飾角色ConcreteDecorate
class FlyCar extends SuperCar {
public FlyCar(Icar car) {
super(car);
}
public void fly() {
System.out.println("天上飛");
}
@Override
public void move() {
super.move();
fly();
}
}
class WaterCar extends SuperCar {
public WaterCar(Icar car) {
super(car);
}
public void swim() {
System.out.println("水上游");
}
@Override
public void move() {
super.move();
swim();
}
}
class AICar extends SuperCar {
public AICar(Icar car) {
super(car);
}
public void autoRun() {
System.out.println("自動跑");
}
@Override
public void move() {
super.move();
autoRun();
}
}
Client
package com.decorate;
public class Client {
public static void main(String[] args) {
Car car = new Car();
car.move();
System.out.println("------增加新的功能:天上飛------");
FlyCar flyCar = new FlyCar(car);
flyCar.move();
System.out.println("------增加新的功能:水上游------");
WaterCar waterCar = new WaterCar(car);
waterCar.move();
System.out.println("------增加兩個新的功能:自動天上飛------");
AICar aiCar = new AICar(new FlyCar(car));
aiCar.move();
}
}
結果
陸地上跑
------增加新的功能:天上飛------
陸地上跑
天上飛
------增加新的功能:水上游------
陸地上跑
水上游
------增加兩個新的功能:自動天上飛------
陸地上跑
天上飛
自動跑
IO流實現細節:
1)Conponent抽象構件角色
io流中InputStream、OutputStream、Reader、Writer
2)ConcreteComponent具體構件角色
io流中FileInputStream、FileOutputStream
3)DEcorator裝飾角色
持有一個抽象構件的引用:io流中的FilterInoutStream、FilterOutputStream
4)ConcreteDecorator具體裝飾角色
負責給構件物件增加新的責任,io流中的BufferdInputStream、BufferedOutputStream
開發中使用場景:
1)io輸入流和輸出流的設計
2)Swing包中圖形介面構建功能
3)Servlet API中提供一個request物件的Decorator設計模式的預設實現類HttpServletrequestWrapper,增強request物件功能
總結:裝飾模式也叫包裝器模式;裝飾模式降低系統的耦合度,可以動態的增加或刪除物件職責,並使得需要裝飾的具體構件類和具體裝飾類可以獨立變化,一邊則更加新的具體構件類和具體裝飾類
優點:
1)擴充套件對物件功能,比繼承靈活,不會導致類個數急劇增加
2)可以對一個物件進行多次裝飾,創造出不同行為的組合,得到功能更加強大的物件
3)具體構件類和具體裝飾類可以獨立變化,,使用者可以根據自己需要增加新的具體構件子類和具體裝飾子類
缺點:
1)產生很多小物件,大量小物件佔據記憶體,一定程度上影響效能
2)裝飾模式易於出錯,除錯排查比較麻煩
裝飾模式和橋接模式的區別:
都是為了解決過多子類物件問題,橋接模式是物件自身現有機制沿著多個維度變化,有部分不穩定;裝飾模式是為了增加新的功能