適配器模式(對象適配器學習筆記)

  1. 意圖

  將一個類的接口裝換成客戶但願的另一個接口java

  2. 動機

  有時,爲複用而設計的工具類不可以被複用僅僅是由於它的接口與專業應用領域所須要的接口不匹配。Adapter常常還要負責提供那些被匹配的類所沒有提供的功能(有點相似裝飾模式)ide

  3. 適用性

  • 想使用一個已經存在的類,而它的接口不符合你的需求
  • 想要建立一個能夠複用的類,該類能夠與其餘不相關的類或不可預見的類(即那些接口可能不必定兼容的類)協同工做
  • 複用一些類,它們處於同一繼承體系,而且又有了一些共同的方法,可是這些共同的方法不是全部這一繼承體系中的子類所共有的。不可能對每個都進行子類化以匹配它們的接口。對象適配器能夠適配它的父類接口

  4. 結構

  

  5. 效果

  1) 容許一個Adapter與多個Adaptee——Adaptee自己以及它的全部子類——同時工做。Adapter能夠一次給全部的Adaptee添加功能函數

  2) 使得重定義Adapter的行爲比較困難。這就須要生成Adaptee的子類,而且使得Adapter引用這個子類而不是Adaptee自己工具

  3) 單一職責原則_你能夠將接口或數據轉換代碼從程序主要業務邏輯中分離this

  4) 開閉原則。 只要客戶端代碼經過客戶端接口與適配器進行交互, 你就能在不修改現有客戶端代碼的狀況下在程序中添加新類型的適配器spa

  6. 代碼實現

  讓方釘適配圓孔

  round/RoundHole.java: 圓孔設計

package adapter.round;

/**
 * @author GaoMing
 * @date 2021/7/12 - 9:07
 * RoundHoles are compatible with RoundPegs.
 */
public class RoundHole {
    private double radius;

    public RoundHole(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }

    public boolean fits(RoundPeg peg) {
        boolean result;
        result = (this.getRadius() >= peg.getRadius());
        return result;
    }
}

  round/RoundPeg.java: 圓釘  代理

package adapter.round;

/**
 * @author GaoMing
 * @date 2021/7/12 - 9:07
 */
public class RoundPeg {
    private double radius;

    public RoundPeg() {}

    public RoundPeg(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }
}

  square/SquarePeg.java: 方釘code

package adapter.square;

/**
 * @author GaoMing
 * @date 2021/7/12 - 9:08
 * SquarePegs are not compatible with RoundHoles (they were implemented by
 * previous development team). But we have to integrate them into our program.
 */
public class SquarePeg {
    private double width;

    public SquarePeg(double width) {
        this.width = width;
    }

    public double getWidth() {
        return width;
    }

    public double getSquare() {
        double result;
        result = Math.pow(this.width, 2);
        return result;
    }
}

  adapters/SquarePegAdapter.java: 方釘到圓孔的適配器xml

package adapter.adapters;

import adapter.round.RoundPeg;
import adapter.square.SquarePeg;

/**
 * @author GaoMing
 * @date 2021/7/12 - 9:25
 * Adapter allows fitting square pegs into round holes.
 */
public class SquarePegAdapter extends RoundPeg {
    private SquarePeg peg;

    public SquarePegAdapter(SquarePeg peg) {
        this.peg = peg;
    }

    @Override
    public double getRadius() {
        double result;
        // Calculate a minimum circle radius, which can fit this peg.
        result = (Math.sqrt(Math.pow((peg.getWidth() / 2), 2) * 2));
        return result;
    }
}

  Demo.java: 客戶端代碼

package adapter;

import adapter.adapters.SquarePegAdapter;
import adapter.round.RoundHole;
import adapter.round.RoundPeg;
import adapter.square.SquarePeg;

/**
 * @author GaoMing
 * @date 2021/7/12 - 9:07
 */
public class Demo {
    public static void main(String[] args) {
        // Round fits round, no surprise.
        RoundHole hole = new RoundHole(5);
        RoundPeg rpeg = new RoundPeg(5);
        if (hole.fits(rpeg)) {
            System.out.println("Round peg r5 fits round hole r5.");
        }

        SquarePeg smallSqPeg = new SquarePeg(2);
        SquarePeg largeSqPeg = new SquarePeg(20);
        // hole.fits(smallSqPeg); // Won't compile.

        // Adapter solves the problem.
        SquarePegAdapter smallSqPegAdapter = new SquarePegAdapter(smallSqPeg);
        SquarePegAdapter largeSqPegAdapter = new SquarePegAdapter(largeSqPeg);
        if (hole.fits(smallSqPegAdapter)) {
            System.out.println("Square peg w2 fits round hole r5.");
        }
        if (!hole.fits(largeSqPegAdapter)) {
            System.out.println("Square peg w20 does not fit into round hole r5.");
        }
    }
}

  執行結果  

Round peg r5 fits round hole r5.
Square peg w2 fits round hole r5.
Square peg w20 does not fit into round hole r5.

 

  7. 與其餘模式的關係

  • 橋接模式一般會於開發前期進行設計, 使你可以將程序的各個部分獨立開來以便開發。 另外一方面, 適配器模式一般在已有程序中使用, 讓相互不兼容的類能很好地合做
  • 適配器能夠對已有對象的接口進行修改, 裝飾模式則能在不改變對象接口的前提下強化對象功能。 此外, 裝飾還支持遞歸組合, 適配器則沒法實現
  • 適配器能爲被封裝對象提供不一樣的接口, 代理模式能爲對象提供相同的接口, 裝飾則能爲對象提供增強的接口 
  • 外觀模式爲現有對象定義了一個新接口, 適配器則會試圖運用已有的接口。 適配器一般只封裝一個對象, 外觀一般會做用於整個對象子系統上

  8. 已知應用

  適配器模式在 Java 代碼中很常見。 基於一些遺留代碼的系統經常會使用該模式。 在這種狀況下, 適配器讓遺留代碼與現代的類得以相互合做  

  • java.util.Arrays#asList()
  • java.util.Collections#list()
  • java.util.Collections#enumeration()
  • java.io.InputStreamReader(InputStream) (返回 Reader對象)
  • java.io.OutputStreamWriter(OutputStream) (返回 Writer對象)
  • javax.xml.bind.annotation.adapters.XmlAdapter#marshal() 和 #unmarshal()

  識別方法: 適配器能夠經過以不一樣抽象或接口類型實例爲參數的構造函數來識別。 當適配器的任何方法被調用時, 它會將參數轉換爲合適的格式, 而後將調用定向到其封裝對象中的一個或多個方法

相關文章
相關標籤/搜索