大家好,我们今天来一起学习一个新的设计模式,叫做媒介模式。
所谓的媒介其实是一种封装的思想,把某些功能共同的逻辑抽象出来做成一个中间的媒介,从而减少代码之间的耦合,提升拓展性,更加方便日后的需求变更。
简单案例
我们用一个实际的例子来认知一下媒介这个设计模式。
假设我们要做一个聊天室,如果真要去做的话,这里面会非常复杂,涉及到很多网络编程的知识,比如广播、客户端、服务端等等。为了方便演示,我们把这些都简化了。这样简化到极致之后,我们的聊天室代码就只有几行:
class User: def __init__(self, name): self.name = name def say(self, message): call_something() print('[{} says:] {}'.format(self.name, message))
这段逻辑没什么好说的,大家应该都能看懂。假设我们就这么完成了产品经理的需求,会有一个什么问题呢?
功能上当然是OK的,但是系统设计上有两个比较大的问题。第一个是逻辑重复的问题,我们在User也就是聊天室中用户对象的类当中实现了怎么在聊天室当中聊天的功能。我们会发现用户之间的私聊,用户之间的视频、语言等可能都会用到差不多的逻辑,比如建立网络连接,比如发送消息,判断消息是否发送成功等等。
但是现在这些逻辑是写死在User这个类里了,如果其他类想要使用,根本没法复用,只能把代码拷贝一份。这样拷贝来拷贝去就会使得代码变得非常混乱,变得难以维护。
第二个问题是逻辑耦合的问题,User这个类是聊天室的用户对象类,但是其中实现了很多聊天室的功能。表面上看是简单了,但其实是聊天室和用户这两个不同概念的代码耦合在一起了。很多垃圾项目都有这个问题,明明A本身就应该是一个单独的实体,结果我却需要去修改B当中的代码。时间一长,连开发者自己都会忘记当初实现某某的逻辑放在哪里。
通过对这个案例的分析,其实也是对为什么要使用设计模式这个问题的回答。设计模式大多数情况下并不能直接提升项目的运行效率,它最大的功能是为了代码的拓展性以及可维护性。如果不使用合理的设计模式,随着功能的增多,项目代码和逐渐变得越来越臃肿,直到人类难以维护的地步。
媒介模式
回归正题,那么我们怎么样来使用媒介设计模式来解决上面的这两个问题呢?
其实很简单,我们直接来看代码吧:
class ChatRoom: def display_message(self, user, message): print('[{} says]: {}'.format(user, message))class User: def __init__(self, name): self.name = name self.chat_room = ChatRoom() def say(self, message): self.chat_room.display_message(self, message)
也就是说我们抽象出了一个ChatRoom这个类,将聊天室的功能从User类当中剥离了出去,并且将它作为了User类的一个成员变量。这样做的好处是,当以后聊天室的功能需要复用或者是需要修改的时候,我们可以避免对User类的打扰。不然的话,开发人员需要在User类的一堆代码当中准确找到聊天室的相关逻辑进行修改,相信我,这绝不是什么很好的体验。
当然,到这里并没有优化到极致,由于User这个类的实例很多,我们会发现每次我们创建一个User的实例都会产生一个ChatRoom的实例,这其实是非常多余并且没有必要的。所以我们可以把ChatRoom设计成单例模式,不管User创建多少实例,获得的ChatRoom都是同一个,这样就节省了内存开销。
我们用单例模式来改写一下ChatRoom的代码:
import threadingclass ChatRoom: _lock = threading.Lock() def __init__(self): pass def __new__����,��Ҫ(cls, *algs, **kw): if not hasattr(ChatRoom, '_instance'): with ChatRoom._lock: if not hasattr(ChatRoom, '_instance'): ChatRoom._instance = object.__new__(cls) return ChatRoom._instance
到这里,这个问题才算是被优化到了极限。看似很简单的一个功能,其实当中涉及的细节和思考还是很多的,绝不是表面上看起来的那么简单,这些内容书本上往往是学不到的,只能通过自己的实践和思考来获得。
今天的文章就到这里,衷心祝愿大家每天都有所收获。如果还喜欢今天的内容的话,请来一个三连支持吧~(点赞、在看、转发)