Java设计模式透析之 —— 适配器(Adapter)

今天一大早,你的leader就匆匆忙忙跑过来找到你:“快,快,紧急任务!近期ChinaJoy立即就要開始了。老板要求提供一种直观的方式,能够查看到我们新上线的游戏中每一个服的在线人数。


你看了看日期,不是吧!

这哪里是立即要開始了,分明是已经開始了!

这怎么可能来得及呢?

“没关系的。”你的leader安慰你道:“功能事实上非常easy的,接口都已经提供好了。你仅仅须要调用一下即可了。


好吧,你勉为其难地接受了,对于这样的突如其来的新需求。你早已习惯。

你的leader向你详细描写叙述了一下需求,你们的游戏眼下有三个服。一服已经开放一段时间了,二服和三服都是新开的服。设计的接口很轻便。你仅仅须要调用Utility.getOnlinePlayerCount(int)。传入每一个服相应的数值就能够获取到相应服在线玩家的数量了,如一服传入1。二服传入2。三服则传入3。

假设你传入了一个不存在的服,则会返回-1。然后你仅仅要将得到的数据拼装成XML就好。详细的显示功能由你的leader来完毕。

好吧,听起来功能并非非常复杂,假设如今就開始动工好像还来得及,于是你立即敲起了代码。

首先定义一个用于统计在线人数的接口PlayerCount,代码例如以下:

[java] view plaincopy
  1. public interface PlayerCount {  
  2.   
  3.     String getServerName();  
  4.   
  5.     int getPlayerCount();  
  6.   
  7. }  
接着定义三个统计类实现了PlayerCount接口,分别相应了三个不同的服,例如以下所看到的:
[java] view plaincopy
  1. public class ServerOne implements PlayerCount {  
  2.   
  3.     @Override  
  4.     public String getServerName() {  
  5.         return "一服";  
  6.     }  
  7.   
  8.     @Override  
  9.     public int getPlayerCount() {  
  10.         return Utility.getOnlinePlayerCount(1);  
  11.     }  
  12.   
  13. }  
[java] view plaincopy
  1. public class ServerTwo implements PlayerCount {  
  2.   
  3.     @Override  
  4.     public String getServerName() {  
  5.         return "二服";  
  6.     }  
  7.   
  8.     @Override  
  9.     public int getPlayerCount() {  
  10.         return Utility.getOnlinePlayerCount(2);  
  11.     }  
  12.   
  13. }  
[java] view plaincopy
  1. public class ServerThree implements PlayerCount {  
  2.   
  3.     @Override  
  4.     public String getServerName() {  
  5.         return "三服";  
  6.     }  
  7.   
  8.     @Override  
  9.     public int getPlayerCount() {  
  10.         return Utility.getOnlinePlayerCount(3);  
  11.     }  
  12.   
  13. }  
然后定义一个XMLBuilder类,用于将各服的数据封装成XML格式,代码例如以下:
[java] view plaincopy
  1. public class XMLBuilder {  
  2.   
  3.     public static String buildXML(PlayerCount player) {  
  4.         StringBuilder builder = new StringBuilder();  
  5.         builder.append("<root>");  
  6.         builder.append("<server>").append(player.getServerName()).append("</server>");  
  7.         builder.append("<player_count").append(player.getPlayerCount()).append("</player_count>");  
  8.         builder.append("</root>");  
  9.         return builder.toString();  
  10.     }  
  11.   
  12. }  
这种话,全部代码就完工了,假设你想查看一服在线玩家数仅仅须要调用:
[java] view plaincopy
  1. XMLBuilder.buildXML(new ServerOne());  
查看二服在线玩家数仅仅须要调用:
[java] view plaincopy
  1. XMLBuilder.buildXML(new ServerTwo());  
查看三服在线玩家数仅仅须要调用:
[java] view plaincopy
  1. XMLBuilder.buildXML(new ServerThree());  

咦?你发现查看一服在线玩家数的时候,返回值永远是-1。查看二服和三服都非常正常。

你仅仅好把你的leader叫了过来:“我感觉我写的代码没有问题。可是查询一服在线玩家数总是返回-1。为什么会这样呢?”

“哎呀!”你的leader猛然想起。“这是我的问题。前面没跟你解释清楚。因为我们的一服已经开放一段时间了。查询在线玩家数量的功能早就有了,使用的是ServerFirst这个类。当时写Utility.getOnlinePlayerCount()这种方法主要是为了针对新开的二服和三服,就没把一服的查询功能再反复做一遍。”

听到你的leader这么说,你顿时松了一口气:“那你改动一下Utility.getOnlinePlayerCount()就好了。应该没我什么事了吧?”

“晤。。。

本来应该是这种。

。。但是,Utility和ServerFirst这两个类都已经被打到Jar包里了,没法改动啊。。

。”你的leader有些为难。

“什么?这不是坑爹吗,难道要我把接口给改了?”你已经泪流满面了。

“这倒不用。这样的情况下能够使用适配器模式,这个模式就是为了解决接口之间不兼容的问题而出现的。

事实上适配器模式的使用很easy,核心思想就是仅仅要能让两个互不兼容的接口能正常对接即可了。上面的代码中,XMLBuilder中使用PlayerCount这个接口来拼装XML,而ServerFirst并没有实现PlayerCount这个接口,这个时候就须要一个适配器类来为XMLBuilder和ServerFirst之间搭起一座桥梁。毫无疑问,ServerOne就将充当适配器类的角色。改动ServerOne的代码,例如以下所看到的:

[java] view plaincopy
  1. public class ServerOne implements PlayerCount {  
  2.       
  3.     private ServerFirst mServerFirst;  
  4.       
  5.     public ServerOne() {  
  6.         mServerFirst = new ServerFirst();  
  7.     }  
  8.   
  9.     @Override  
  10.     public String getServerName() {  
  11.         return "一服";  
  12.     }  
  13.   
  14.     @Override  
  15.     public int getPlayerCount() {  
  16.         return mServerFirst.getOnlinePlayerCount();  
  17.     }  
  18.   
  19. }  
这样通过ServerOne的适配,XMLBuilder和ServerFirst之间就成功完毕对接了!

使用的时候我们甚至无需知道有ServerFirst这个类,仅仅须要正常创建ServerOne的实例即可了。


须要值得注意的一点是。适配器模式不并是那种会让架构变得更合理的模式,很多其它的时候它仅仅是充当救火队员的角色,帮助解决因为前期架构设计不合理导致的接口不匹配的问题。更好的做法是在设计的时候就尽量把以后可能出现的情况多考虑一些,在这个问题上不要向你的leader学习。


适配器:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本因为接口不兼容而不能一起工作的那些类能够一起工作。

posted on 2017-06-13 18:07  ljbguanli  阅读(155)  评论(0)    收藏  举报