当前位置:首页>编程知识库>后端开发知识>设计模式是什么鬼(中介)
设计模式是什么鬼(中介)
阅读 1
2018-10-21
中介,作用于多个事物之间充当交互沟通的媒介。我们的生活中有各种各样的媒介,比如一些传统媒体,书刊杂志,报纸,把信息传递给读者。再比如利用电子信息技术的互联网,作为一种新媒体,不单可以更高效地把信息传递给用户,而且可以反向地获得用户反馈评论,用户与用户之间亦可以进行沟通,这种全终端双向互通是传统媒体所不能及的。
除此之外,再如婚介所、房产中介、交换机组网、现代电子商务、C2C购物平台、手机、即时通软件等等,这些都与我们的生活息息相关,离开它们我们将举步维艰。其实不管是任何中介,其本质都是相同的,都是充当中间媒介的角色,并达成多方业务互通的目的。
首先我们以最简单的模型来解决问题,以两个人交谈为例,其实他们之间并不需要任何第三方媒介,而是一对一直接沟通,看代码。
%201public%20class%20People%20%7B%0A%202%20%20private%20String%20name;//%E7%94%A8%E5%90%8D%E5%AD%97%E6%9D%A5%E5%8C%BA%E5%88%AB%E4%BA%BA%E3%80%82%0A%203%20%20private%20People%20other;//%E6%8C%81%E6%9C%89%E5%AF%B9%E6%96%B9%E7%9A%84%E5%BC%95%E7%94%A8%E3%80%82%0A%204%0A%205%20%20public%20String%20getName()%20%7B%0A%206%20%20%20%20return%20this.name;%0A%207%20%20%7D%0A%208%0A%209%20%20public%20People(String%20name)%20%7B%0A10%20%20%20%20this.name%20=%20name;//%E5%88%9D%E5%A7%8B%E5%8C%96%E5%BF%85%E9%A1%BB%E8%B5%B7%E5%90%8D%E3%80%82%0A11%20%20%7D%0A12%0A13%20%20public%20void%20connect(People%20other)%20%7B%0A14%20%20%20%20this.other%20=%20other;//%E8%BF%9E%E6%8E%A5%E6%96%B9%E6%B3%95%E4%B8%AD%E6%B3%A8%E5%85%A5%E5%AF%B9%E6%96%B9%E5%BC%95%E7%94%A8%E3%80%82%0A15%20%20%7D%0A16%0A17%20%20public%20void%20talk(String%20msg)%20%7B%0A18%20%20%20%20other.listen(msg);//%E6%88%91%E6%96%B9%E8%AF%B4%E8%AF%9D%E6%97%B6%EF%BC%8C%E5%AF%B9%E6%96%B9%E8%81%86%E5%90%AC%E3%80%82%0A19%20%20%7D%0A20%0A21%20%20public%20void%20listen(String%20msg)%20%7B%0A22%20%20%20%20//%E8%81%86%E5%90%AC%E6%9D%A5%E8%87%AA%E5%AF%B9%E6%96%B9%E7%9A%84%E5%A3%B0%E9%9F%B3%0A23%20%20%20%20System.out.println(%0A24%20%20%20%20%20%20%20%20other.getName()%20 %20%22%20%E5%AF%B9%20%22%20 %20this.name%20 %20%22%20%E8%AF%B4%EF%BC%9A%22%20 %20msg%0A25%20%20%20%20);%0A26%20%20%7D%0A27%7D%0A
一切就绪,两人开始沟通。
%201public%20class%20Main%20%7B%0A%202%20%20public%20static%20void%20main(String%20args%5B%5D)%20%7B%0A%203%20%20%20%20People%20p3%20=%20new%20People(%22%E5%BC%A0%E4%B8%89%22);%0A%204%20%20%20%20People%20p4%20=%20new%20People(%22%E6%9D%8E%E5%9B%9B%22);%0A%205%0A%206%20%20%20%20p3.connect(p4);%0A%207%20%20%20%20p4.connect(p3);%0A%208%0A%209%20%20%20%20p3.talk(%22%E4%BD%A0%E5%A5%BD%E3%80%82%22);%0A10%20%20%20%20p4.talk(%22%E6%97%A9%E4%B8%8A%E5%A5%BD%EF%BC%8C%E4%B8%89%E5%93%A5%E3%80%82%22);%0A11%20%20%7D%0A12%20%20/****************************%0A13%20%20%E8%BE%93%E5%87%BA%E7%BB%93%E6%9E%9C%EF%BC%9A%0A14%20%20%20%20%E5%BC%A0%E4%B8%89%20%E5%AF%B9%20%E6%9D%8E%E5%9B%9B%20%E8%AF%B4%EF%BC%9A%E4%BD%A0%E5%A5%BD%E3%80%82%0A15%20%20%20%20%E6%9D%8E%E5%9B%9B%20%E5%AF%B9%20%E5%BC%A0%E4%B8%89%20%E8%AF%B4%EF%BC%9A%E6%97%A9%E4%B8%8A%E5%A5%BD%EF%BC%8C%E4%B8%89%E5%93%A5%E3%80%82%0A16%20%20*****************************/%0A17%7D%0A
People类中我们可以看到,沟通只只能在两人之间进行,而且各自都持有对方对象的引用,以便把消息传递给对方的监听方法。这种模式虽然简单,但耦合性太强,你中有我,我中有你,谁也离不开谁。试想如果再有多个人加入交谈,那每个人都要持有其他所有人的引用了,这时会陷入一种多对多的关联陷阱,对象关系变得复杂不堪,如蛛网般难以维护。
我们就拿群聊天室举例,每当有人加入或离开,都要把每个人持有的其他人的引用关系更新一遍,发消息时更是繁琐不堪,重复工作显得非常多余。那么如何解决这个问题呢?我们开始进行思考,为何不把重复的部分抽离出来呢,也就是把对方的引用放在一个中介类里面去统一维护起来,于是设计更改如下。
可以看到,每个用户不再所持有其他所有用户的引用了,取而代之的是聊天室的引用,这样引用关系瞬间变得明朗起来,开始我们的代码重构。
%201public%20class%20User%20%7B%0A%202%20%20%20%20private%20String%20name;//%E5%90%8D%E5%AD%97%0A%203%0A%204%20%20%20%20private%20ChatRoom%20chatRoom;//%E8%81%8A%E5%A4%A9%E5%AE%A4%E5%BC%95%E7%94%A8%0A%205%0A%206%20%20%20%20public%20User(String%20name)%20%7B%0A%207%20%20%20%20%20%20%20%20this.name%20=%20name;//%E5%88%9D%E5%A7%8B%E5%8C%96%E5%BF%85%E9%A1%BB%E8%B5%B7%E5%90%8D%E5%AD%97%0A%208%20%20%20%20%7D%0A%209%0A10%20%20%20%20public%20String%20getName()%20%7B%0A11%20%20%20%20%20%20%20%20return%20this.name;%0A12%20%20%20%20%7D%0A13%0A14%20%20%20%20public%20void%20login(ChatRoom%20chatRoom)%20%7B//%E7%94%A8%E6%88%B7%E7%99%BB%E9%99%86%0A15%20%20%20%20%20%20%20%20chatRoom.connect(this);//%E8%B0%83%E7%94%A8%E8%81%8A%E5%A4%A9%E5%AE%A4%E8%BF%9E%E6%8E%A5%E6%96%B9%E6%B3%95%0A16%20%20%20%20%20%20%20%20this.chatRoom%20=%20chatRoom;//%E6%B3%A8%E5%85%A5%E8%81%8A%E5%A4%A9%E5%AE%A4%E5%BC%95%E7%94%A8%0A17%20%20%20%20%7D%0A18%0A19%20%20%20%20public%20void%20talk(String%20msg)%20%7B//%E7%94%A8%E6%88%B7%E5%8F%91%E8%A8%80%0A20%20%20%20%20%20%20%20%20chatRoom.sendMsg(this,%20msg);//%E7%BB%99%E8%81%8A%E5%A4%A9%E5%AE%A4%E5%8F%91%E6%B6%88%E6%81%AF%0A21%20%20%20%20%7D%0A22%0A23%20%20%20%20public%20void%20listen(User%20fromWhom,%20String%20msg)%20%7B//%E4%B8%94%E5%90%AC%E9%A3%8E%E5%90%9F%0A24%20%20%20%20%20%20%20%20System.out.print(%22%E3%80%90%22 this.name %22%E7%9A%84%E5%AF%B9%E8%AF%9D%E6%A1%86%E3%80%91%22);%0A25%20%20%20%20%20%20%20%20System.out.println(fromWhom.getName()%20 %20%22%20%E8%AF%B4%EF%BC%9A%20%22%20 %20msg);%0A26%20%20%20%20%7D%0A27%7D%0A
可以看到第14行,用户登陆聊天室时不再是连接对方了,而是连接通知聊天室并告知:“有人进来了请进行注册”,然后记录下来用户当前所在聊天室的引用。第19行,用户发言时也不是直接找对方了,而是把消息扔给聊天室处理。第23行,聆听方法同样也是,将来会接受来自聊天室的声音。很显然,一切沟通都与是中介聊天室进行,这样用户之间就实现了解耦的目的。当然,用户当然还需要注销离开聊天室,请读者可自行练习添加,下面接着写我们的聊天室中介类。
%201public%20class%20ChatRoom%20%7B%0A%202%20%20%20%20private%20String%20name;//%E8%81%8A%E5%A4%A9%E5%AE%A4%E5%91%BD%E5%90%8D%0A%203%0A%204%20%20%20%20public%20ChatRoom(String%20name)%20%7B%0A%205%20%20%20%20%20%20%20%20this.name%20=%20name;//%E5%88%9D%E5%A7%8B%E5%8C%96%E5%BF%85%E9%A1%BB%E5%91%BD%E5%90%8D%E8%81%8A%E5%A4%A9%E5%AE%A4%0A%206%20%20%20%20%7D%0A%207%0A%208%20%20%20%20List<User>%20users%20=%20new%20ArrayList<>();//%E8%81%8A%E5%A4%A9%E5%AE%A4%E9%87%8C%E7%9A%84%E7%94%A8%E6%88%B7%E4%BB%AC%0A%209%0A10%20%20%20%20public%20void%20connect(User%20user)%20%7B%0A11%20%20%20%20%20%20%20%20this.users.add(user);//%E7%94%A8%E6%88%B7%E8%BF%9B%E5%85%A5%E8%81%8A%E5%A4%A9%E5%AE%A4%E5%8A%A0%E5%85%A5%E5%88%97%E8%A1%A8%E3%80%82%0A12%20%20%20%20%20%20%20%20System.out.print(%22%E6%AC%A2%E8%BF%8E%E3%80%90%22);%0A13%20%20%20%20%20%20%20%20System.out.print(user.getName());%0A14%20%20%20%20%20%20%20%20System.out.println(%22%E3%80%91%E5%8A%A0%E5%85%A5%E8%81%8A%E5%A4%A9%E5%AE%A4%E3%80%90%22%20 %20this.name%20 %20%22%E3%80%91%22);%0A15%20%20%20%20%7D%0A16%0A17%20%20%20%20public%20void%20sendMsg(User%20fromWhom,%20String%20msg)%20%7B%0A18%20%20%20%20%20%20%20%20//%20%E5%BE%AA%E7%8E%AF%E6%89%80%E6%9C%89%E7%94%A8%E6%88%B7%EF%BC%8C%E5%8F%AA%E5%8F%91%E6%B6%88%E6%81%AF%E7%BB%99%E9%9D%9E%E5%8F%91%E9%80%81%E6%96%B9fromWhom%E3%80%82%0A19%20%20%20%20%20%20%20%20users.stream()%0A20%20%20%20%20%20%20%20%20.filter(user%20->%20!user.equals(fromWhom))//%E8%BF%87%E6%BB%A4%E6%8E%89%E5%8F%91%E9%80%81%E6%96%B9fromWhom%0A21%20%20%20%20%20%20%20%20.forEach(toWhom%20->%20toWhom.listen(fromWhom,%20msg));//%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%E7%BB%99%E5%89%A9%E4%B8%8B%E7%9A%84%E6%89%80%E6%9C%89%E4%BA%BA%0A22%20%20%20%20%7D%0A23%7D%0A
这里我们新建一个聊天室作为中介类,所有参与者登陆时调用第10行的connect方法进入聊天室,并记录其引用到users列表中。第17行,当用户发消息到平台我们再转发给其他人,这里利用Java8的流和Lambda表达式进行过滤(User类的equals方法请自行加入),并循环调用所有接收方的listen方法即可。
为了说明问题,我们这里只是保持最简单的方式,如果某天情况变得复杂,有了不同的用户,或是聊天室也各不相同并加入了各自的特性,那我们就需要继续重构,抽象聊天室类,抽象用户类,读者可以灵活运用,这里就不做赘述了。
其实中介模式不止是在生活中广泛应用,在软件架构中也非常常见,当下流行的微服务分布式软件架构所用到的注册中心,例如最常用到的云组件Eureka Server,其作用就是为众多分布式服务提供注册发现服务,它正是充当像中介一样的角色。
还记得之前讲到的组合模式中的树型结构吧,它主要描述的是子节点与父节点的关系。
而中介模式更像是网络拓扑中的星型结构,它描述了众节点与中心点的关系。
对像之间显式地互相引用越多,意味着依赖性越强,独立性越差,不利于代码维护与扩展,同时多方沟通的任务也应交由中间平台来完成,每个类应只具备各自该有的功能,这便是高内聚低耦合的设计标准。中介模式符合迪米特法则,它解决了对象间过度耦合、复杂频繁交互的问题,打破了你中有我,我中有你的相互依赖,第三方的介入有助于双方调停,打破如胶似漆、纠缠不休的关系,让他们之间变得松散、自由、独立。
点击图片加入Java知音交流群
↓↓↓
看完本文有收获?请转发分享给更多人
以上数据来源于网络,如有侵权,请联系删除。
评论 (0)