设计模式-适配器模式-以电压适配器为例

超级链接: Java常用设计模式的实例学习系列-绪论

参考:《HeadFirst设计模式》


1.关于适配器模式

适配器模式是一种结构型模式。

适配器模式:将一个类的接口转换成客户期望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

下面以一张经典的图来描述适配器模式:

在这里插入图片描述

本文以电压适配器为场景来学习适配器模式

  • 手机充Phone电需要的电压是5V的。
  • 充电宝PortableBatteryPower提供的电源是5V的,所以手机可以直接通过充电宝进行充电。
  • 家用电源HouseholdPower提供的电压是220V的,所有手机不能直接通过家用电源进行充电。
  • 通过电压适配器,可以将家用电源的220V电源转换为手机充电可用的5V电源。

2.手机与充电宝

假定现在有充电宝,则可以直接进行手机充电。

分析上面的场景,其实手机充电依赖的不仅仅是充电宝,而是依赖的一种5V的电源。

所以,首先,我们定义一个5V的电源,并以充电宝作为一种实现。

5V电源:接口:V5Power

/**
 * <p>5V的电源</P>
 *
 * @author hanchao
 */
public interface V5Power {
    /**
     * 获取名称
     */
    String getName();

    /**
     * 获取电压
     */
    Integer getVoltage();
}

5V电源:实现:充电宝:PortableBatteryPower

/**
 * <p>充电宝</P>
 *
 * @author hanchao
 */
public class PortableBatteryPower implements V5Power {

    @Override
    public String getName() {
        return "充电宝";
    }

    @Override
    public Integer getVoltage() {
        return 5;
    }
}

然后,定义一个手机Phone,它具有充电功能batteryCharge(),其能接受的参数是V5Power类型的。

/**
 * <p>手机</P>
 *
 * @author hanchao
 */
@Slf4j
public class Phone {
    /**
     * 充电
     */
    public void batteryCharge(V5Power v5Power) {
        log.info("1.连接电源 ==> " + v5Power.getName());
        log.info("2.当前电压 : " + v5Power.getVoltage());
        log.info("3.进行充电 ... ");
    }
}

最后,我们写一段测试代码:AdapterDemo

    public static void main(String[] args) {
        //首先,需要一部手机
        Phone phone = new Phone();

        log.info("如果有充电宝,则直接用它充电");
        V5Power v5Power = new PortableBatteryPower();
        phone.batteryCharge(v5Power);
    }

运行结果

2019-07-09 12:44:03,556  INFO [main-1] pers.hanchao.designpattern.adapter.AdapterDemo:22 - 如果有充电宝,则直接用它充电 
2019-07-09 12:44:03,560  INFO [main-1] pers.hanchao.designpattern.adapter.Phone:19 - 1.连接电源 ==> 充电宝 
2019-07-09 12:44:03,560  INFO [main-1] pers.hanchao.designpattern.adapter.Phone:20 - 2.当前电压 : 5 
2019-07-09 12:44:03,560  INFO [main-1] pers.hanchao.designpattern.adapter.Phone:21 - 3.进行充电 ... 

3.手机与家用电源

假定现在只有家用电源,则不能直接进行手机充电。

分析上面的场景,其实手机不仅仅不能通过家用电源直接充电,所有220V的电源都不能直接用于手机充电。

所以,我们定义一个220V的电源,并以家用电源作为一种实现。

220V电源:接口:V220Power

/**
 * <p>220V的电源</P>
 *
 * @author hanchao
 */
public interface V220Power {
    /**
     * 获取名称
     */
    String getName();

    /**
     * 获取电压
     */
    Integer getVoltage();
}

220V电源:实现:家用电源:HouseholdPower

/**
 * <p>家用电源</P>
 *
 * @author hanchao
 */
public class HouseholdPower implements V220Power {

    @Override
    public String getName() {
        return "家用电源";
    }

    @Override
    public Integer getVoltage() {
        return 220;
    }
}

因为手机Phone的充电方法batteryCharge(V5Power v5Power)参数是V5Power类型的,肯定无法直接传入V220Power类型的参数。

4.适配器

此时,我们需要实现一个适配器Adapter,这个适配器应该实现以下两个功能:

  • 它的类型应是V5Power的,如此才能作为batteryCharge()方法的参数。所以有:Adapter implements V5Power
  • 它应包含V220Power的对象,如此才能实现最初的目的:使用V220的电源。所以有成员变量:V220Power v220Power

上面所描述的,其实就是开始的示例图中的那句话:适配器本身包含接口乙,并实现了接口甲。

根据这个思路,很容易实现适配器代码。

适配器:V220=>V5:V220ToV5Adapter

/**
 * <p>USB接口转换器</P>
 * <p>
 * 1.实现适配目标对象V5Power
 *
 * @author hanchao
 */
@Slf4j
public class V220ToV5Adapter implements V5Power {
    /**
     * 2.以组合的方式持有被适配对象v220Power
     */
    private V220Power v220Power;

    /**
     * 3.在构造时初始化被适配对象v220Power
     */
    public V220ToV5Adapter(V220Power v220Power) {
        this.v220Power = v220Power;
    }

    /**
     * 重写V5Power的方法,完成V220到V5的转换过程
     */
    @Override
    public String getName() {
        return " 电源适配器 ==> " + v220Power.getName();
    }

    /**
     * 重写V5Power的方法,完成V220到V5的转换过程
     */
    @Override
    public Integer getVoltage() {
        log.info("原始电压为:" + v220Power.getVoltage());
        log.info("进行电压转换:" + v220Power.getVoltage() + " --> " + 5);
        log.info("转换之后的电源为:5");
        return 5;
    }
}

测试代码:AdapterDemo

    public static void main(String[] args) {
        //首先,需要一部手机
        Phone phone = new Phone();
        log.info("如果只有家用电源,则需要通过电源适配器进行转换");
        V220Power v220Power = new HouseholdPower();
        v5Power = new V220ToV5Adapter(v220Power);
        phone.batteryCharge(v5Power);
    }

测试结果

2019-07-09 13:01:44,981  INFO [main-1] pers.hanchao.designpattern.adapter.AdapterDemo:26 - 如果只有家用电源,则需要通过电源适配器进行转换 
2019-07-09 13:01:44,985  INFO [main-1] pers.hanchao.designpattern.adapter.Phone:18 - 1.连接电源 ==>  电源适配器 ==> 家用电源 
2019-07-09 13:01:44,985  INFO [main-1] pers.hanchao.designpattern.adapter.adapter.V220ToV5Adapter:41 - 原始电压为:220 
2019-07-09 13:01:44,986  INFO [main-1] pers.hanchao.designpattern.adapter.adapter.V220ToV5Adapter:42 - 进行电压转换:220 --> 5 
2019-07-09 13:01:44,986  INFO [main-1] pers.hanchao.designpattern.adapter.adapter.V220ToV5Adapter:43 - 转换之后的电源为:5 
2019-07-09 13:01:44,986  INFO [main-1] pers.hanchao.designpattern.adapter.Phone:19 - 2.当前电压 : 5 
2019-07-09 13:01:44,986  INFO [main-1] pers.hanchao.designpattern.adapter.Phone:20 - 3.进行充电 ...

5.总结

最后以UML类图来总结本文的电压适配器场景以及适配器模式。

在这里插入图片描述

适配器模式遵循了一条很重要的OOP原则,那就是:多用组合,少用继承

适配器模式,能够有效的解决接口不兼容问题。

适配器模式的优点:

  • 解耦:将不兼容接口客户端解耦,两者都不必修改原有代码。
  • 灵活性高、扩展性好:如果当前适配器不适用,重新编写一个新的适配器即可。
  • 增加代码复用性高:接口本来不能复用,在适配之后,则可以被复用。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值