写点什么

【设计模式】适配器模式:攻敌三分,自留七分,以超兽武装的例子来谈谈适配器模式

作者:游坦之
  • 2022-11-27
    山东
  • 本文字数:3409 字

    阅读完需:约 11 分钟

1 适配器模式

1.1 定义

将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能在一起工作的那些类能一起工作。

适配器模式分为类适配器模式对象适配器模式,前者类(类适配器)之间的耦合度比后者高,而且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对少一些

1.2 结构

  • 目标接口(Target):当前系统业务所期待的接口,它可以是抽象类或者接口。

  • 适配者类(Adaptee):他是被访问和适配的现存组件库中的组件接口。

  • 适配器类(Adapter):它是一个转换器,通过**继承(类)或引用(对象)**适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。


个人认为:适配器的作用就是让用户使用 A 的功能而达到 B 功能的效果。

1.3 类图

1.3.1 类适配器模式

1.3.2 对象适配器模式

为什么要有对象适配器模式,因为类适配器模式违反了合成/聚合复用原则,也就是优先考虑组合/聚合来实现复用,其次考虑继承(使用继承需要严格遵循里氏代换原则,滥用继承会增加系统构建和维护的难度以及系统的复杂度)


2 例子


国产动画片《超兽武装》中的角色就很符合适配器模式。他们可以以普通模式进行战斗,也可以通过异能锁(适配器)来召唤超兽武装进行战斗。角色(如龙戬)想要发送技能--寒影决,通过异能锁,将其变成了威力更为强大的超兽形态寒影决。


普通形态的龙戬


也可以攻击和使用寒影决



异能锁


借助异能锁,超兽武装,将自己的寒影决变成超兽武装的寒影决,威力更大



超兽武装


可以攻击、使用超兽状态下的寒影决


2.1 类适配器模式

2.1.1 代码

在此例子中,有四个重要的角色 龙戬(DargonJian)、普通形态(Common)、超兽武装形态(Mocha)、异能锁(PowerLock)。使用适配器的目的即为龙戬在使用普通形态的技能时底层调用的是超兽武装形态的技能方法。

至于为什么是类适配器模式而不是对象适配器模式,核心就在于在将普通形态接口转化成超兽武装形态的过程中,适配器类继承了超兽武装形态的实现类,而不是创建一个超兽武装形态类的对象。


Common.interface


/* 普通状态 */public interface Common {    /* 攻击 */    void attack();    /* 大招 */    void bigMove(String msg);
}
复制代码


CommonImpl.java


/* 普通形态类 */public class CommonImpl implements Common {
@Override public void attack() { System.out.println("稀里哗啦做了一套广播体操,对敌人造成了1点伤害"); }
@Override public void bigMove(String msg) { System.out.println("放出了大招"+msg); }}
复制代码


Mocha.interface


/* 超兽武装 */public interface Mocha {    /* 攻击 */    void attack();    /* 大招 */    void bigMove(String msg);}
复制代码


MochaImpl.java


/** 超兽武装* */public class MochaImpl implements Mocha {
@Override public void attack() { System.out.println("超兽武装形态下对敌攻击,造成1W点伤害"); }
@Override public void bigMove(String msg) { System.out.println("超兽武装形态下放出了大招"+msg); }}
复制代码


PowerLock.java


/** 异能锁:适配器* */public class PowerLock extends MochaImpl implements Common {
@Override public void attack() {
super.attack(); }
@Override public void bigMove(String msg) { super.bigMove(msg); }}
复制代码


DargonJian.java


public class DragonJian {    /* 龙戬攻击 */    public void attack(Common common)    {        if(common == null)        {            throw new NullPointerException("没有普通形态");        }        common.attack();    }    /* 寒影决 */    public void bigMove(Common common,String msg)    {        if(common == null)        {            throw new NullPointerException("没有普通形态");        }        common.bigMove(msg);    }}
复制代码


Client.java


public class Client {    public static void main(String[] args) {        /* 龙戬 */        DragonJian dragonJian = new DragonJian();        /* 普通攻击*/        dragonJian.attack(new CommonImpl());        dragonJian.bigMove(new CommonImpl(),"寒影决");        System.out.println("=====借助异能锁,超兽武装=====");        dragonJian.attack(new PowerLock());        dragonJian.bigMove(new PowerLock(),"寒影决");    }

}
复制代码

2.1.2 效果图

2.2 对象适配器模式

这里为了符合合成/聚合复用原则,将原有的继承改成了组合/聚合的形式

2.2.1 代码

Client.java


public class Client {    public static void main(String[] args) {        /* 龙戬 */        DragonJian dragonJian = new DragonJian();        /* 普通攻击*/        dragonJian.attack(new CommonImpl());        dragonJian.bigMove(new CommonImpl(),"寒影决");        System.out.println("=====借助异能锁,超兽武装=====");        PowerLock powerLock = new PowerLock(new MochaImpl());        dragonJian.attack(powerLock);        dragonJian.bigMove(powerLock,"寒影决");    }

}
复制代码


Common.java


/* 普通状态 */public interface Common {    /* 攻击 */    void attack();    /* 大招 */    void bigMove(String msg);
}
复制代码


CommonImpl.java


/* 普通形态类 */public class CommonImpl implements Common {
@Override public void attack() { System.out.println("稀里哗啦做了一套广播体操,对敌人造成了1点伤害"); }
@Override public void bigMove(String msg) { System.out.println("放出了大招"+msg); }}
复制代码


DragonJian.java


public class DragonJian {    /* 龙戬攻击 */    public void attack(Common common)    {        if(common == null)        {            throw new NullPointerException("没有普通形态");        }        common.attack();    }    /* 寒影决 */    public void bigMove(Common common, String msg)    {        if(common == null)        {            throw new NullPointerException("没有普通形态");        }        common.bigMove(msg);    }}
复制代码


Mocha.java


/* 超兽武装 */public interface Mocha {    /* 攻击 */    void attack();    /* 大招 */    void bigMove(String msg);}
复制代码


MochaImpl.java


/** 超兽武装* */public class MochaImpl implements Mocha {
@Override public void attack() { System.out.println("超兽武装形态下对敌攻击,造成1W点伤害"); }
@Override public void bigMove(String msg) { System.out.println("超兽武装形态下放出了大招"+msg); }}
复制代码


PowerLock.java


/** 异能锁:适配器* */public class PowerLock implements Common {
MochaImpl mocha = new MochaImpl();
public PowerLock(MochaImpl mocha) { this.mocha = mocha; }
@Override public void attack() {
mocha.attack(); }
@Override public void bigMove(String msg) { mocha.bigMove(msg); }}
复制代码

2.2.2 效果通

3 优缺点及适用环境

3.1 优点

  • 一个对象适配器可以把多个不同的适配器适配到同一个目标

  • 可以适配一个适配者的子类,由于适配器和适配者之间是关联关系,根据"里氏代换原则",适配者的子类也可以通过该适配器进行适配。

  • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无需修改原有的代码。增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。

3.2 缺点

  • 对于 Java、C#等不支持多重类继承的语言,一次最多只能适配一个适配者类,不能同时适配多个适配者。

  • 在 Java、C#等语言中,类适配者模式中的目标抽象类只能为接口,不能为类,其使用有一定的局限性。

3.3 适用环境

系统需要使用现有的类,而这些类的接口不符合系统的需要。想要建立一个可以重复使用的类,用于一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作。是关联关系,根据"里氏代换原则",适配者的子类也可以通过该适配器进行适配。

用户头像

游坦之

关注

还未添加个人签名 2022-10-14 加入

还未添加个人简介

评论

发布
暂无评论
【设计模式】适配器模式:攻敌三分,自留七分,以超兽武装的例子来谈谈适配器模式_软件工程_游坦之_InfoQ写作社区