设计模式(一)—— 适配器模式
一、定义
二、适用的场景
三、注意事项
四、模式中的角色
- 目标接口(Target):客户期待的接口
- 需要适配的类(Adaptee):需要被适配的类
- 适配器(adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。实现方法是适配器类继承需要适配的类,并实现目标接口
五、应用场景举例
public interface ICompanyA { //获取员工ID public String getID(); //获取员工姓名 public String getName(); public String getPhone(); public String getAddress(); }
2、现在A公司需要将一部分业务外包给B公司,B公司的一部分开发人员也会归A的员工管理系统来管
但是B公司自己本身也有一套管理系统,主要代码如下
public interface ICompanyB { //获取员工ID public Map getIDB(); //获取员工姓名 public Map getInfo(); public Map getTel(); public Map getHome(); }
public class CompanyB implements ICompanyB{ public Map getTel() { HashMap hashMap = new HashMap(); hashMap.put("tel", "151xxxx"); return hashMap; } public Map getHome() { HashMap hashMap = new HashMap(); hashMap.put("home", "shandong"); return hashMap; } public Map getIDB() { HashMap hashMap = new HashMap(); hashMap.put("id", "100"); return hashMap; } public Map getInfo() { HashMap hashMap = new HashMap(); hashMap.put("info", "fzj"); return hashMap; } }
3、A公司的系统要获得B公司系统的数据,但由于数据格式不同
这时就需要有一个中转角色,来对其进行转换,这里就用到了我们所讲的适配器模式
public class Adapter extends CompanyB implements ICompanyA{ private Map home = super.getHome(); private Map id = super.getIDB(); private Map name = super.getInfo(); private Map tel = super.getTel(); public String getName() { return (String) name.get("info"); } public String getPhone() { return (String) tel.get("tel"); } public String getAddress() { return (String) home.get("home"); } public String getID() { return (String) home.get("id"); } }
4、以上的代码已经解决了两个接口不一致的问题,但是接下来思考一个问题:如果B公司使用了三个接口来负责员工信息管理的,而java又不支持多继承,这个问题要怎么解决
案例二
如果B公司使用了两个或多个接口来负责员工信息管理的,而java又不支持多继承,这个问题要怎么解决?
这里假设一个场景,我们公司使用A公司和B公司的接口,需要使用适配器整合这两家公司的接口来适配我们公司的接口
A公司的接口
public class CompanyA { private List<Person> person; public List<Person> getPerson() { return person; } public void setPerson(List<Person> person) { this.person = person; } }
B公司的接口
public class CompanyB { private Map<String,Person> personMap; public Map<String, Person> getPersonMap() { return personMap; } public void setPersonMap(Map<String, Person> personMap) { this.personMap = personMap; } }
我们公司的接口
public interface CompanyOur { List<OurPerson> getPerson(); }
这里可以使用一个整合类来调用A公司和B公司的对象
public class CompanyAll { private CompanyA companyA; private CompanyB companyB; public CompanyA getCompanyA() { return companyA; } public void setCompanyA(CompanyA companyA) { this.companyA = companyA; } public CompanyB getCompanyB() { return companyB; } public void setCompanyB(CompanyB companyB) { this.companyB = companyB; } }
实现对A、B公司的适配器
public class Client extends CompanyAll implements CompanyOur { private CompanyA companyA = getCompanyA(); private CompanyB companyB = getCompanyB(); @Override public List<OurPerson> getPerson() { List<OurPerson> list = new ArrayList<>(); companyA.getPerson().forEach( person -> { OurPerson ourPerson = new OurPerson(); ourPerson.setOurName(person.getName()); ourPerson.setOurHome(person.getHome()); list.add(ourPerson); } ); companyB.getPersonMap().forEach( (x, y) -> { OurPerson ourPerson = new OurPerson(); ourPerson.setOurName(y.getName()); ourPerson.setOurHome(y.getHome()); list.add(ourPerson); }); return list; } }
案例三
看《HeadFirst设计模式》一书中有一个挺逗的例子。原话是这样。
如果它走起路来像只鸭子,叫起来像只鸭子,那么他可能是一只包装了鸭子适配器的火鸡。
其实在现实生活中,你也可以成为适应任何人。比如,你身边有一个朋友天天吐槽,经常会说“holy shit”,“真倒霉”,你不喜欢他,但又不得不跟他生活在一起,这是你就可以在自己脑袋里装一个适配器,通过适配器,你会将抱怨转换为感谢、赞美。比如他说“倒霉”,经过适配器,你会想他说的是“真幸运”。时间久了,你会觉得他是乐观向上的人。说明你适配了他。
简短的说明,如何实现鸭子的例子。火鸡适配器类肯定是要实现鸭子接口的,引用火鸡对象,对接口方法进行实现。
参考
[1] 《设计模式之禅》 秦小波
[2] 《HeadFirst设计模式》
[3] 平时代码中用不到设计模式?Are you kidding me?
关于作者
后端程序员,五年开发经验,从事互联网金融方向。技术公众号「清泉白石」。如果您在阅读文章时有什么疑问或者发现文章的错误,欢迎在公众号里给我留言。