对适配器模式的理解

本文介绍了适配器模式,一种解决接口不兼容问题的设计模式,通过提供适配器让不同数据类型的对象能够互相配合。以Java为例,展示了如何在客户端代码中使用适配器处理方钉与圆洞匹配的问题。
摘要由CSDN通过智能技术生成

一、适配器模式是什么?

  • 适配器模式是一种结构型设计模式, 它能使接口不兼容的对象能够相互合作。
  • 背景1:
    • 客户端通过接口A处理数据A,但是用户可能传入数据B。
    • 一种解决方案是:为数据B实现接口B。但这样做的话,需要修改客户端的代码(尽量不修改上层代码)。而且接口B不一定好实现。
    • 另一种解决方案是:提供适配器,让数据B去适配接口A。
  • 背景2:
    • 客户端传入数据A,然而,系统中只有处理数据B的接口B。
    • 因此,需要提供适配器,让数据A去适配接口B。
  • 类比:生活中,iphone用的是Lightning接口,而很多充电器已经是type-c了。这就需要Lightning转type-c的适配器。

二、示例【来源

  • 需求:判断圆洞能否匹配圆钉(假设这是第三方依赖提供的能力)
    • 但是用户还会传入的是方钉(这怎么复用呢?)

1 第三方依赖 (接口A + 数据A)

接口A:RoundHole::fits
数据A:RoundPeg

@Data
@AllArgsConstructor
public class RoundHole {
    private double radius;

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

@Data
@NoArgsConstructor
@AllArgsConstructor
public class RoundPeg {
    private double radius;
}

2 客户端

public class Application {
    public static void main(String[] args) {
        // 判断圆洞能否匹配圆钉(假设这是第三方依赖提供的能力)
        RoundHole roundHole = new RoundHole(2D);
        List<RoundPeg> roundPegs = ImmutableList.of(
                new RoundPeg(1D),
                new RoundPeg(3D)
        );
        roundPegs.stream().forEach(roundPeg -> {
            if (roundHole.fits(roundPeg)) {
                System.out.println(String.format("半径为%.2f的圆钉可以插入半径为%.2f的圆洞种", roundPeg.getRadius(), roundHole.getRadius()));
            } else {
                System.out.println(String.format("半径为%.2f的圆钉不能插入半径为%.2f的圆洞种", roundPeg.getRadius(), roundHole.getRadius()));
            }
        });
    }
}

3 方钉转圆钉的适配器(数据B)

@Data
@AllArgsConstructor
public class SquarePeg {
    private double width;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class SquarePegAdapter extends RoundPeg {
    private SquarePeg squarePeg;

    /**
     * public boolean fits(RoundPeg peg) {
     *     return this.radius >= peg.getRadius();
     * }
     *
     * 从客户端使用方式可知,SquarePegAdapter需要继承RoundPeg,并且覆写getRadius()方法。
     */

    @Override
    public double getRadius() {
        return squarePeg.getWidth() * Math.sqrt(2) / 2;
    }
}
  • 客户端代码:
public class Application {
    public static void main(String[] args) {
        // 判断圆洞能否匹配圆钉(假设这是第三方依赖提供的能力)
        RoundHole roundHole = new RoundHole(2D);
        List<RoundPeg> roundPegs = ImmutableList.of(
                new RoundPeg(1D),
                new RoundPeg(3D)
        );
        roundPegs.stream().forEach(roundPeg -> {
            if (roundHole.fits(roundPeg)) {
                System.out.println(String.format("半径为%.2f的圆钉可以插入半径为%.2f的圆洞种", roundPeg.getRadius(), roundHole.getRadius()));
            } else {
                System.out.println(String.format("半径为%.2f的圆钉不能插入半径为%.2f的圆洞种", roundPeg.getRadius(), roundHole.getRadius()));
            }
        });

        // 但是用户还会传入的是方钉(这怎么复用呢?)
        List<SquarePeg> squarePegs = ImmutableList.of(
                new SquarePeg(1D),
                new SquarePeg(3D)
        );

        SquarePegAdapter squarePegAdapter = new SquarePegAdapter();
        squarePegs.stream().forEach(squarePeg -> {
            squarePegAdapter.setSquarePeg(squarePeg);
            if (roundHole.fits(squarePegAdapter)) {
                System.out.println(String.format("半径为%.2f的方钉可以插入半径为%.2f的圆洞种", squarePeg.getWidth(), roundHole.getRadius()));
            } else {
                System.out.println(String.format("半径为%.2f的方钉不能插入半径为%.2f的圆洞种", squarePeg.getWidth(), roundHole.getRadius()));
            }
        });
    }
}

/**
半径为1.00的圆钉可以插入半径为2.00的圆洞中
半径为3.00的圆钉不能插入半径为2.00的圆洞中
半径为1.00的方钉可以插入半径为2.00的圆洞中
半径为3.00的方钉不能插入半径为2.00的圆洞中
*/

三、适配器(xxxAdapter)怎么写?

  • 思路:
  • (1)从客户端代码入手,确定什么是不变的。
public boolean fits(RoundPeg peg) {
	return this.radius >= peg.getRadius();
}

如果fits()方法不变,那么就得将SquarePeg适配成RoundPeg

  • (2)确定被适配对象
    • SquarePeg,方法取名为SquareAdapter
  • (3)实现SquareAdapter
public class SquarePegAdapter extends RoundPeg {
    private SquarePeg squarePeg;
    
    @Override
    public double getRadius() {
        return squarePeg.getWidth() * Math.sqrt(2) / 2;
    }
}
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值