設計模式—結構型模式

關注公衆號獲取更多資料
在這裏插入圖片描述html

@java

設計模式—結構型模式

​ 結構型模式描述如何將類或者對象按照某種佈局組成更大的結構。組合關係或者聚合關係的耦合度比繼承低,知足「合成複用原則」。結構型模式主要有如下幾種:設計模式

  1. 代理模式:爲某對象提供一種代理以控制對該對象的訪問,用戶經過代理訪問該對象。
  2. 適配器模式:將一個類的接口轉換成用戶但願的另外一種接口,使得本來接口不兼容的可以一塊兒工做起做用。
  3. 橋接模式:將抽象和實現分離,使他們能夠獨立變化,用組合關係代替繼承關係。
  4. 裝飾模式:動態的給對象增長一些功能。
  5. 外觀模式:爲多個複雜的子系統提供一個一致的接口,是之更加容易被訪問。
  6. 享元模式:運用共享技術支持大量重複對象中共享元素的複用。
  7. 組合模式:將對象組合成樹結構的模式,使用戶可以對整體對象和子對象具備一直的訪問性。

代理模式

​ 代理模式在框架中很常見,Spring AOP就是經過代理模式實現的 。安全

​ 代理模式主要有如下幾個角色:app

  1. 抽象主題:經過接口或者抽象類聲明須要代理的類的方法。
  2. 真實主題:須要被代理的類,須要實現抽象主題。
  3. 代理類:實現了抽象主題,並在聲明的代理方法中實現被代理類的方法,在原有的方法上進行額外的操做。

​ 代理模式的類結構以下:框架

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-lTjMpSLj-1604422625547)(結構型模式.assets/代理模式.png)]

​ 舉例說明:ide

  • 建立抽象主題
interface ProxyInterface {
    void say();
}
  • 建立真實主題
class RealObject implements ProxyInterface {
    @Override
    public void say() {
        System.out.println("hello");
    }
}
  • 建立代理類
class ProxyObject implements ProxyInterface {
    RealObject obj;
    @Override
    public void say() {
        if (obj == null) obj = new RealObject();
        preSay();
        obj.say();
        afterSay();
    }
    private void preSay() {
        System.out.println("proxy in...");
    }
    private void afterSay() {
        System.out.println("proxy out...");
    }
}
  • 測試
public class ProxyDemo {
    public static void main(String[] args) {
        ProxyObject proxy = new ProxyObject();
        proxy.say();
    }
}
//輸出
//proxy in...
//hello
//proxy out...

​ 在代理類中使用了真實主題對象,並在調用方法先後執行代理方法。代理類主要做用是隱藏了真實主題,在必定程度上起到了保護做用。oop

適配器模式

​ 適配器模式是將一個類的接口轉換爲用戶但願的另外一個接口,解決了由於接口不兼容而不能一塊兒工做的問題。通常狀況下能夠分爲類適配器和對象適配器兩種。佈局

​ 適配器主要包含如下幾個結構:測試

  1. 目標接口:用戶所但願的接口,能夠是抽象類或者接口。
  2. 適配者:現存的組件,即須要被兼容的組件。
  3. 適配器:將適配者轉換成目標接口的樣式的類。

類適配器

​ 類適配器經過繼承和實現接口的方式完成適配過程,類圖以下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-XUl0Qnii-1604422625550)(結構型模式.assets/類適配器.png)]

​ 舉例說明:

  • 建立目標接口
interface Adapter {
    void request();
}
  • 建立適配者
class Adaptee {
    public void say() {
        System.out.println("hello from adapdee");
    }
}
  • 建立適配者
class ClassAdapter extends Adaptee implements Adapter {
    @Override
    public void request() {
        say();
    }
}
  • 測試
Adapter classAdapter = new ClassAdapter();
classAdapter.request();//hello from adapdee

對象適配器

​ 對象適配器,只實現了目標接口,而後在適配器中依賴適配者,使用適配者調用原有方法實現適配的方式,類結構以下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xUSCWZGb-1604422625551)(結構型模式.assets/對象適配器.png)]

擴展--雙向適配器

​ 雙向適配器能夠將適配者轉換爲目標,也能夠將目標轉換爲適配者。他的適配器類採用對象適配器實現,以下:

class TwoWayAdapter implements Adapter, IAdaptee {
    private Adaptee adaptee;
    private Adapter adapter;

    public TwoWayAdapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    public TwoWayAdapter(Adapter adapter) {
        this.adapter = adapter;
    }

    @Override
    public void request() {
        System.out.println("適配器調用適配者...");
        adaptee.say();
    }

    @Override
    public void say() {
        System.out.println("適配者調用適配器");
        adapter.request();
    }
}

​ 測試:

System.out.println("--------");
TwoWayAdapter twoWayAdapter = new TwoWayAdapter(new ObjectAdapter(new Adaptee()));
twoWayAdapter.say();//hello from adapdee
System.out.println("--------");
TwoWayAdapter twoWayAdapter1 = new TwoWayAdapter(new Adaptee());
twoWayAdapter1.request();//hello from adapdee

橋接模式

​ 現實生活中不少對象都是由多種元素組成,這些元素又會有多種變化,若是採用繼承的方式將會產生不少種不一樣的類,使系統臃腫冗餘。好比一個產品有兩種元素組成,這兩種元素分別有m種和n種種類,那麼若是使用繼承方式,將會有m*n種可能性。

​ 橋接模式將抽象和實現分離,使他們能夠獨立變化,使用組合關係替代繼承,下降了多可變的狀況。

​ 橋接模式主要包含如下幾個結構:

  1. 抽象化角色:定義抽象類,包含一個對實現化對象的引用。
  2. 擴展抽象化:抽象化角色的子類,實現弗雷中的業務,並調用實現化對象的業務方法。
  3. 實現化角色:定義實現化角色的接口。
  4. 具體實現化:實現化角色的具體實現。

​ 橋接模式的類圖:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-vmEnnPp0-1604422625553)(結構型模式.assets/橋接模式.png)]

​ 舉例說明:女式揹包有不少種種類,好比手提包,錢包等等,也有不少種顏色,使用橋接模式能夠很方便的對這些屬性進行組合。

  • 建立抽象化角色
abstract class Bag {
    public Color color;
    public Bag(Color color) {
        this.color = color;
    }
    abstract String getName();
    public void say() {
        System.out.println("i am " + getName() + ";my color is " + color.getColor());
    }
}
  • 擴展抽象化角色
class HandBag extends Bag {
    @Override
    String getName() {
        return "handBag";
    }
    public HandBag(Color color) {
        super(color);
    }
}

class Wallet extends Bag {
    @Override
    String getName() {
        return "wallet";
    }
    public Wallet(Color color) {
        super(color);
    }
}
  • 實現化角色接口
interface Color {
    String getColor();
}
  • 具體實現化角色
class Red implements Color {
    @Override
    public String getColor() {
        return "red";
    }
}

class Yellow implements Color {
    @Override
    public String getColor() {
        return "yellow";
    }
}
  • 測試
Bag handBag = new HandBag(new Red());
handBag.say();
Bag wallet = new Wallet(new Yellow());
wallet.say();
//i am handBag;my color is red
//i am wallet;my color is yellow

裝飾模式

​ 裝飾者模式是指在不改變現有對象結構的狀況下,動態的對其增長一些職責的模式。

​ 裝飾者模式有如下幾個成員:

  1. 抽象構件:定義一個抽象接口準備接受附加責任的對象。
  2. 具體構件:實現抽象構件,經過裝飾角色增長一些職責。
  3. 抽象裝飾:繼承抽象構件,包含具體構件的實例。
  4. 具體裝飾:實現抽象裝飾的一些方法。

​ 裝飾者模式的類圖:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-WIiaeDuv-1604422625554)(結構型模式.assets/裝飾者模式.png)]

​ 裝飾者模式與代理模式都是在不改變原有類結構的基礎上新增一些職責,二者功能一致,從類圖上看,結構也很類似。

​ 裝飾者模式關注於在一個對象上動態的添加方法,然而代理模式關注於控制對對象的訪問。換句話 說,用代理模式,代理類能夠對它的客戶隱藏一個對象的具體信息。所以,當使用代理模式的時候,咱們經常在一個代理類中建立一個對象的實例。而且,當咱們使用裝飾器模 式的時候,咱們一般的作法是將原始對象做爲一個參數傳給裝飾者的構造器。

​ 能夠用另一句話來總結這些差異:使用代理模式,代理和真實對象之間的的關係一般在編譯時就已經肯定了,而裝飾者可以在運行時遞歸地被構造。http://www.cnblogs.com/jaredlam/archive/2011/11/08/2241089.html)

​ 舉例說明:汽車的生產—汽車對象Car,在出廠的時候能夠添加修飾,使之成爲不一樣類型的車輛。

  • 抽象構件
interface Car {
    void create();
}
  • 具體構件
class MyCar implements Car {
    @Override
    public void create() {
        System.out.print("it's a car.");
    }
}
  • 抽象裝飾
abstract class DecoratorCar implements Car {
    private Car car;
    public DecoratorCar(Car car) {
        this.car = car;
    }
    @Override
    public void create() {
        car.create();
    }
    abstract void change();
}
  • 具體裝飾
class Truck extends DecoratorCar {
    public Truck(Car car) {
        super(car);
    }
    public void create() {
        super.create();
        change();
    }
    @Override
    protected void change() {
        System.out.println("it's a truck.");
    }
}

class Bus extends DecoratorCar {
    public Bus(Car car) {
        super(car);
    }
    @Override
    public void create() {
        super.create();
        change();
    }
    @Override
    void change() {
        System.out.println("it's a bus.");
    }
}
  • 測試
Car truck = new Truck(new MyCar());
truck.create();
//it's a car.it's a truck.
Car bus = new Bus(new MyCar());
bus.create();
//it's a car.it's a truck.

​ 裝飾模式在Java中最著名的應用就是I/O庫的設計了,例如InputStream的子類FileInputStream,OutputStream的子類FileOutputStream等,他們都是裝飾類。

外觀模式

​ 外觀模式是一種經過爲多個複雜的子系統提供一個一致的接口,使這些子系統更容易被訪問。

​ 外觀模式一般有如下幾種角色:

  1. 外觀角色:爲多個子系統對外提供一個共同接口。
  2. 子系統角色:實現系統的部分功能。
  3. 客戶角色:經過外觀角色訪問各個子系統的功能。

​ 外觀模式類圖以下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MaW0WERm-1604422625555)(結構型模式.assets/外觀模式1.png)]

​ 舉例說明:京東購買流程包含下單,付款,打包等子系統支持

  • 客戶角色
class User {
    private JDShopping jd = new JDShopping();
    public void buy() {
        jd.shooping();
    }
}
  • 外觀角色
class JDShopping {
    private ChooseSystem chooseSystem = new ChooseSystem();
    private PaySystem paySystem = new PaySystem();
    private PackageSystem packageSystem = new PackageSystem();
    public void shooping() {
        chooseSystem.choose();
        paySystem.pay();
        packageSystem.packageGoods();
    }
}
  • 子系統角色
class ChooseSystem {
    public void choose() {
        System.out.println("下單中...");
    }
}

class PaySystem {
    public void pay() {
        System.out.println("付款中...");
    }
}

class PackageSystem {
    public void packageGoods() {
        System.out.println("打包中...");
    }
}
  • 測試
public static void main(String[] args) {
    new User().buy();
    //下單中...
    //付款中...
    //打包中...
}

擴展

​ 若是須要引入其餘子系統,可使用以下結構:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-QkRlyvwr-1604422625557)(結構型模式.assets/外觀模式2.png)]

享元模式

​ 享元模式運用了共享技術最大限度的支持大量細粒度對象的複用。享元模式主要有如下幾個角色:

  1. 抽象享元角色:全部具體享元類的基類,爲具體享元的公共接口。
  2. 具體享元角色:實現抽象享元角色中規定的接口。
  3. 非享元角色:不可共享的外部狀態。
  4. 享元工廠角色:負責建立和管理享元角色。

​ 享元模式的類圖以下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-rqEEfJKI-1604422625558)(結構型模式.assets/享元模式.png)]

​ 舉例說明:以圍棋爲例,黑白棋子除顏色之外都具有相同的屬性,非享元角色爲顏色,剩餘爲享元角色。

  • 非享元角色
class PiecesColor {
    private String color;
    public PiecesColor(String color) {
        this.color = color;
    }
    public String getColor() {
        return color;
    }
    @Override
    public int hashCode() {
        return this.color.hashCode();
    }
    @Override
    public boolean equals(Object color) {
        return this.color.equals(((PiecesColor) color).getColor());
    }
}
  • 抽象享元角色
abstract class Pieces {
    protected String shareName = "share";
    protected PiecesColor color;
    public Pieces(PiecesColor color) {
        this.color = color;
    }
    public String getShareName() {
        return shareName;
    }
    public PiecesColor getColor() {
        return color;
    }
    public void show() {
        System.out.println(this + "--shareName:" + shareName + "--color:" + color.getColor());
    }
}
  • 具體享元角色
class WhitePieces extends Pieces {
    public WhitePieces(PiecesColor color) {
        super(color);
    }
}

class BlackPieces extends Pieces {
    public BlackPieces(PiecesColor color) {
        super(color);
    }
}
  • 享元工廠角色
class PiecesFactory {
    //能夠用任何形式儲存
    Map<PiecesColor, Pieces> pieces = new HashMap<>(2);
    public Pieces get(PiecesColor color) {
        if (!pieces.containsKey(color)) {
            System.out.println("creating...");
            pieces.put(color, color.getColor().equals("white") ? new WhitePieces(color) : new BlackPieces(color));
        }
        return pieces.get(color);
    }
}
  • 測試
PiecesFactory factory = new PiecesFactory();
Pieces pieces = factory.get(new PiecesColor("white"));
pieces.show();
pieces = factory.get(new PiecesColor("black"));
pieces.show();
//是否再也不建立享元角色,使用現有對象
pieces = factory.get(new PiecesColor("white"));
pieces.show();
pieces = factory.get(new PiecesColor("black"));
pieces.show();
  • 結果
creating...
com.wupengchoy.mystudy.designpattern.structure.WhitePieces@255316f2--shareName:share--color:white
creating...
com.wupengchoy.mystudy.designpattern.structure.BlackPieces@41906a77--shareName:share--color:black
com.wupengchoy.mystudy.designpattern.structure.WhitePieces@255316f2--shareName:share--color:white
com.wupengchoy.mystudy.designpattern.structure.BlackPieces@41906a77--shareName:share--color:black

​ 以上結果能夠看出第二次獲取對象的時候享元角色並無從新建立,而是使用以前建立的對象。

組合模式

​ 組合模式又叫部分-總體模式,將對象組合成樹狀的層次結構的模式,表示部分和總體的關係。一般有如下幾個角色:

  1. 抽象構件角色:爲樹葉結構和樹枝結構聲明公共接口,並實現默認行爲。
  2. 樹葉結構角色:組合中的葉子節點對象,沒有子節點。
  3. 樹枝結構對象:組合中的分支節點對象,有子節點。

​ 組合模式的實現方式可分爲透明式和安全式,類圖和區別以下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-D2s2o57v-1604422625560)(結構型模式.assets/組合模式1.png)]

​ 舉例說明:超市購物袋子爲例,大袋子裏有小袋子,還有其餘商品,小袋子裏還有其餘商品。

  • 抽象構件
abstract class BagAndGoods {
    abstract void show();
}
  • 樹葉結構
class Milk extends BagAndGoods {
    public void show() {
        System.out.println("i am milk.");
    }
}

class Apple extends BagAndGoods {
    public void show() {
        System.out.println("i am apple.");
    }
}
  • 樹枝結構
class Bags extends BagAndGoods {
    private List<BagAndGoods> goods = new ArrayList<>();
    public void add(BagAndGoods good) {
        goods.add(good);
    }
    @Override
    public void show() {
        for (BagAndGoods good : goods) {
            good.show();
        }
    }
}
  • 測試
Bags bigBag = new Bags();
bigBag.add(new Milk());
Bags milddleBag = new Bags();
milddleBag.add(new Apple());
milddleBag.add(new Apple());
bigBag.add(milddleBag);
//展現袋子中購買的物品
bigBag.show();
//i am milk.
//i am apple.
//i am apple.

擴展

​ 若是有多個樹枝和樹葉,還能夠對樹枝和樹葉再進行抽象,組成以下格式:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Sgkje2Ku-1604422625562)(結構型模式.assets/組合模式2.png)]

相關文章
相關標籤/搜索