适配器 - 适配器模式的任何真实示例

Aks*_*oop 77 oop design-patterns software-design adapter

我想向我的团队展示Adapter Pattern的使用.我在网上看了很多书和文章.每个人都引用了一个有助于理解概念(形状,记忆卡,电子适配器等)的例子,但没有真正的案例研究.

你能否分享一下适配器模式的案例研究?

ps我尝试在stackoverflow上搜索现有问题,但未找到答案,因此将其作为新问题发布.如果您知道已有答案,请重定向.

Fuh*_*tor 73

适配器的许多例子都是微不足道的或不现实的(Rectangle vs. LegacyRectangle,Ratchet vs. Socket,SquarePeg vs RoundPeg,Duck vs. Turkey).更糟糕的是,许多人没有为不同的Adaptee显示多个Adapters(有人引用Java的Arrays.asList作为适配器模式的一个例子).调整一个类的接口以使用另一个似乎是GoF适配器模式的一个弱例子.这种模式使用继承和多态,因此可以期待一个很好的例子来展示针对不同适应者的多个适配器实现.

我找到的最好的例子应用UML和模式的第26章:面向对象分析和设计和迭代开发的简介(第3版).以下图像来自本书的FTP站点上提供的教师资料.

第一个显示应用程序如何使用功能相似的多个实现(适配器)(例如,税收计算器,会计模块,信用授权服务等),但具有不同的API.我们希望避免硬编码我们的域层代码来处理计算税收,售后,授权信用卡请求等的不同方法.这些都是可能不同的外部模块,我们无法修改码.适配器允许我们在适配器中进行硬编码,而我们的域层代码总是使用相同的接口(IWhateverAdapter接口).

图26.1

我们在上图中没有看到实际的适应者.但是,下图显示了如何postSale(...)在IAccountingAdapter接口中进行多态调用,从而导致通过SOAP将销售过帐到SAP系统.

图26.2


Cou*_*ero 45

如何将法国人变成正常人......

 public interface IPerson
    {
        string Name { get; set; }
    }

    public interface IFrenchPerson
    {
        string Nom { get; set; }
    }

    public class Person : IPerson
    {
        public string Name { get; set; }
    }

    public class FrenchPerson : IFrenchPerson
    {
        public string Nom { get; set; }
    }

    public class PersonService
    {
        public void PrintName(IPerson person)
        {
            Debug.Write(person.Name);
        }
    }

    public class FrenchPersonAdapter : IPerson
    {
        private readonly IFrenchPerson frenchPerson;

        public FrenchPersonAdapter(IFrenchPerson frenchPerson)
        {
            this.frenchPerson = frenchPerson;
        }

        public string Name 
        {
            get { return frenchPerson.Nom; }
            set { frenchPerson.Nom = value; }
        }
    } 
Run Code Online (Sandbox Code Playgroud)

    var service = new PersonService();
    var person = new Person();
    var frenchPerson = new FrenchPerson();

    service.PrintName(person);
    service.PrintName(new FrenchPersonAdapter(frenchPerson));
Run Code Online (Sandbox Code Playgroud)

  • 我是法国人,我觉得你不认为我是一个真实的人.(JK) (16认同)
  • @ZeroUltimax我很确定这段代码不会在魁北克编译. (10认同)
  • 这是关于如何使用我曾经遇到的Adapter模式的最有趣的(也许也是最容易接近的)示例。 (2认同)

Pre*_*raj 42

将接口转换为另一个接口.

适配器模式的任何真实示例

为了连接电源,我们在世界各地都有不同的接口.使用适配器,我们可以轻松地连接.

在此输入图像描述


Eri*_*ang 11

这里是一个可模拟转换的例子analog datadigit data.

它提供了一个将浮点数据转换为二进制数据的适配器,它在现实世界中可能没用,它只是有助于解释适配器模式的概念.


AnalogSignal.java

package eric.designpattern.adapter;

public interface AnalogSignal {
    float[] getAnalog();

    void setAnalog(float[] analogData);

    void printAnalog();
}
Run Code Online (Sandbox Code Playgroud)

DigitSignal.java

package eric.designpattern.adapter;

public interface DigitSignal {
    byte[] getDigit();

    void setDigit(byte[] digitData);

    void printDigit();
}
Run Code Online (Sandbox Code Playgroud)

FloatAnalogSignal.java

package eric.designpattern.adapter;

import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FloatAnalogSignal implements AnalogSignal {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private float[] data;

    public FloatAnalogSignal(float[] data) {
        this.data = data;
    }

    @Override
    public float[] getAnalog() {
        return data;
    }

    @Override
    public void setAnalog(float[] analogData) {
        this.data = analogData;
    }

    @Override
    public void printAnalog() {
        logger.info("{}", Arrays.toString(getAnalog()));
    }
}
Run Code Online (Sandbox Code Playgroud)

BinDigitSignal.java

package eric.designpattern.adapter;

import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BinDigitSignal implements DigitSignal {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private byte[] data;

    public BinDigitSignal(byte[] data) {
        this.data = data;
    }

    @Override
    public byte[] getDigit() {
        return data;
    }

    @Override
    public void setDigit(byte[] digitData) {
        this.data = digitData;
    }

    @Override
    public void printDigit() {
        logger.info("{}", Arrays.toString(getDigit()));
    }
}
Run Code Online (Sandbox Code Playgroud)

AnalogToDigitAdapter.java

package eric.designpattern.adapter;

import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 * Adapter - convert analog data to digit data.
 * </p>
 * 
 * @author eric
 * @date Mar 8, 2016 1:07:00 PM
 */
public class AnalogToDigitAdapter implements DigitSignal {
    public static final float DEFAULT_THRESHOLD_FLOAT_TO_BIN = 1.0f; // default threshold,
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private AnalogSignal analogSignal;
    private byte[] digitData;
    private float threshold;
    private boolean cached;

    public AnalogToDigitAdapter(AnalogSignal analogSignal) {
        this(analogSignal, DEFAULT_THRESHOLD_FLOAT_TO_BIN);
    }

    public AnalogToDigitAdapter(AnalogSignal analogSignal, float threshold) {
        this.analogSignal = analogSignal;
        this.threshold = threshold;
        this.cached = false;
    }

    @Override
    public synchronized byte[] getDigit() {
        if (!cached) {
            float[] analogData = analogSignal.getAnalog();
            int len = analogData.length;
            digitData = new byte[len];

            for (int i = 0; i < len; i++) {
                digitData[i] = floatToByte(analogData[i]);
            }
        }

        return digitData;
    }

    // not supported, should set the inner analog data instead,
    @Override
    public void setDigit(byte[] digitData) {
        throw new UnsupportedOperationException();
    }

    public synchronized void setAnalogData(float[] analogData) {
        invalidCache();
        this.analogSignal.setAnalog(analogData);
    }

    public synchronized void invalidCache() {
        cached = false;
        digitData = null;
    }

    @Override
    public void printDigit() {
        logger.info("{}", Arrays.toString(getDigit()));
    }

    // float -> byte convert,
    private byte floatToByte(float f) {
        return (byte) (f >= threshold ? 1 : 0);
    }
}
Run Code Online (Sandbox Code Playgroud)

代码 - 测试用例

AdapterTest.java

package eric.designpattern.adapter.test;

import java.util.Arrays;

import junit.framework.TestCase;

import org.junit.Test;

import eric.designpattern.adapter.AnalogSignal;
import eric.designpattern.adapter.AnalogToDigitAdapter;
import eric.designpattern.adapter.BinDigitSignal;
import eric.designpattern.adapter.DigitSignal;
import eric.designpattern.adapter.FloatAnalogSignal;

public class AdapterTest extends TestCase {
    private float[] analogData = { 0.2f, 1.4f, 3.12f, 0.9f };
    private byte[] binData = { 0, 1, 1, 0 };
    private float[] analogData2 = { 1.2f, 1.4f, 0.12f, 0.9f };

    @Test
    public void testAdapter() {
        AnalogSignal analogSignal = new FloatAnalogSignal(analogData);
        analogSignal.printAnalog();

        DigitSignal digitSignal = new BinDigitSignal(binData);
        digitSignal.printDigit();

        // adapter
        AnalogToDigitAdapter adAdapter = new AnalogToDigitAdapter(analogSignal);
        adAdapter.printDigit();
        assertTrue(Arrays.equals(digitSignal.getDigit(), adAdapter.getDigit()));

        adAdapter.setAnalogData(analogData2);
        adAdapter.printDigit();
        assertFalse(Arrays.equals(digitSignal.getDigit(), adAdapter.getDigit()));
    }
}
Run Code Online (Sandbox Code Playgroud)

依赖 - 通过maven

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.2</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.13</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.13</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.16</version>
    </dependency>
Run Code Online (Sandbox Code Playgroud)

怎么测试

只需运行单元测试.


小智 7

适配器模式充当两个不兼容接口之间的桥梁.此模式涉及一个称为适配器的类,它负责两个独立或不兼容接口之间的通信.

真实世界的例子可能是语言翻译器或移动充电器.更多此处在youtube视频中:

Youtube - 适配器设计模式:简介


Jaa*_*bax 5

当您必须处理具有相似行为的不同接口(这通常意味着具有相似行为但具有不同方法的类)时,您可以使用适配器设计模式。一个例子是连接到三星电视的类和连接到索尼电视的另一个类。它们将共享公共行为,如打开菜单、开始播放、连接到网络等,但每个库将有不同的实现(具有不同的方法名称和签名)。这些不同的供应商特定实现在 UML 图中称为Adaptee

因此,在您的代码中(在 UML 图中称为Client),而不是硬编码每个供应商(或Adaptee)的方法调用,然后您可以创建一个通用接口(在 UML 图中称为Target)来包装这些类似的行为并工作只有一种类型的对象。

然后,适配器将实现Target接口,将其方法调用委托给通过构造函数传递给适配器Adaptees

为了让您在 Java 代码中实现这一点,我使用与上面提到的完全相同的示例编写了一个非常简单的项目,使用适配器来处理多个智能电视接口。代码很小,有据可查且不言自明,因此深入研究它以了解真实世界的实现会是什么样子。

只需下载代码并将其作为 Maven 项目导入 Eclipse(或您喜欢的 IDE)。您可以通过运行org.example.Main.java来执行代码。请记住,这里重要的是理解类和接口是如何组合在一起来设计模式的。我也创造了一些假Adaptees在包com.thirdparty.libs。希望能帮助到你!

https://github.com/Dannemann/java-design-patterns


Sum*_*ada 5

适配器设计模式有助于将一个类的接口转换为客户期望的接口。

示例: 您有一个服务,通过传递城市名称作为输入值来返回天气(以摄氏度为单位)。现在,假设您的客户想要传递邮政编码作为输入,并期望返回城市的温度。这里你需要一个适配器来实现这一点。

public interface IWetherFinder {
    public double getTemperature(String cityName);
}

class WeatherFinder implements IWetherFinder{
   @Override
   public double getTemperature(String cityName){
     return 40;
   }
}

interface IWeatherFinderClient
{
   public double getTemperature(String zipcode);
}  

public class WeatherAdapter implements IWeatherFinderClient {

    @Override
    public double getTemperature(String zipcode) {

        //method to get cityname by zipcode 
        String cityName = getCityName(zipcode);

        //invoke actual service
        IWetherFinder wetherFinder = new WeatherFinder();
        return wetherFinder.getTemperature(cityName);
    }

    private String getCityName(String zipCode) {
        return "Banaglore";
    }
}
Run Code Online (Sandbox Code Playgroud)