当前位置: 首页 > 后端技术 > Python

【译文】顶级设计模式的Python实现

时间:2023-03-26 17:43:46 Python

在软件开发中,设计模式是针对特定上下文中常见问题的经过验证的解决方案。他们的主要目标是向我们展示一种编程的好方法,并解释为什么其他选项不起作用。使用通用设计模式,您可以:加快开发过程;减少代码行数;确保您的代码设计良好;预见未来由小问题引起的问题。设计模式可以显着改善软件开发人员的生活,无论他或她使用何种编程语言。我采访了Jellyfish.tech的创始人兼CTO,拥有9年以上经验的Python开发人员和软件架构师RomanLatyshenko,了解他的顶级设计模式。我主要使用Python/Django,所以这里列出了我每天在工作中使用的Python设计模式。行为迭代器模式迭代器允许在不暴露内部细节的情况下遍历集合的元素。使用场景。大多数情况下,我使用它来提供一种迭代集合的标准方法。?干净的客户端代码(单一职责原则)。?可以在不改变客户端代码的情况下在集合中引入迭代器(开/闭原则)。?每个迭代对象都有自己的迭代状态,所以可以推迟和继续迭代。?对简单集合使用迭代器会使应用程序过载。结构代码示例from__future__importannotationsfromcollections.abcimportIterable,IteratorfromtypingimportAny,ListclassAlphabeticalOrderIterator(Iterator):_position:int=None_reverse:bool=Falsedef__init__(self,collection:WordsCollection,reverse:bool=False):self._collection=collectionself._reverse=reverseself._position=-1ifreverseelse0def__next__(self):try:value=self._collection[self._position]self._position+=-1ifself._reverseelse1除了IndexError:raiseStopIteration()returnvalueclassWordsCollection(Iterable):def__init__(self,collection:List[Any]=[]):self._collection=collectiondef__iter__(self)->AlphabeticalOrderIterator:returnAlphabeticalOrderIterator(self._collection)defget_reverse_iterator(self)->AlphabeticalOrderIterator:返回AlphabeticalOrderIterator(self._collection,True)defadd_item(self,item:Any):self._collection.append(item)if__name__=="__main__":collection=WordsCollection()collection.add_item("First")collection.add_item("Second")collection.add_item("Third")print("正向遍历:")print("\n".join(collection))print("反向遍历:")print("\n".join(collection.get_reverse_iterator()))状态模式状态模式帮助一个对象在其内部状态改变时改变它的行为使用场景。状态模式帮助我改变了很多对象状态。减少类似转换和状态中重复代码的行数。避免很多情况。?遵循单一职责原则:将与不同状态相关的代码类分开。?在不改变上下文或类状态的情况下添加新状态(开/闭原则)。?当状态机几乎没有变化时,使用状态可能会过多。结构展示示例代码from__future__importannotationsfromabcimportABC,abstractmethodclassContext(ABC):_state=Nonedef__init__(self,state:State):self.transition_to(state)deftransition_to(self,state:State):print(f"上下文:转换为{type(state).__name__}")self._state=stateself._state.context=selfdefrequest1(self):self._state.handle1()defrequest2(self):self._state.handle2()类State(ABC):@propertydefcontext(self)->Context:returnself._context@context.setterdefcontext(self,context:Context):self._context=context@abstractmethoddefhandle1(self):pass@abstractmethoddefhandle2(self):passclassConcreteStateA(State):defhandle1(self):print("ConcreteStateAhandlesrequest1.")print("ConcreteStateA想要改变状态eofthecontext.")self.context.transition_to(ConcreteStateB())defhandle2(self):print("ConcreteStateAhandlesrequest2.")classConcreteStateB(State):defhandle1(self):print("ConcreteStateBhandlesrequest1.")defhandle2(self):print("ConcreteStateBhandlesrequest2.")print("ConcreteStateBwantstochangethestateofthecontext.")self.context.transition_to(ConcreteStateA())if__name__=="__main__":context=Context(ConcreteStateA())context.request1()context.request2()观察者模式观察者通知发生在其他对象中发生的事件,它们观察的对象没有耦合到它们的类使用场景。我每次都用观察者模式需要为对象添加一个订阅机制来订阅/取消订阅特定发布者类上发生的事件的通知。一个很好的例子就是简单地订阅任何在线杂志的新闻,通常你可以选择你感兴趣的领域(科学,数字技术等)。或者,一个“通知我什么时候电子商务平台上的“有货”按钮是另一个例子。?您不必更改发布者的代码即可添加订阅者的类。?订阅者以随机顺序收到通知。结构示例代码from__future__importannotationsfromabcimportABC,abstractmethodfromrandomimportranrangefromtypingimportListclassSubject(ABC):@abstractmethoddefattach(self,observer:Observer):pass@abstractmethoddefdetach(self,observer:Observer):通过@abstractmethoddefnotify(self):passclassConcreteSubject(Subject):_state:int=None_observers:List[Observer]=[]defattach(self,observer:Observer):print("Subject:Attachedanobserver.")self._observers.append(observer)defdetach(self,observer:Observer):self._observers.remove(observer)defnotify(self):print("Subject:Notifyingobservers...")forobserverinself._observers:observer.update(self)defsome_business_logic(self):print("主题:我正在做一些重要的事情。")self._state=randrange(0,10)print(f"Subject:Mystatehasjustchangedto:{self._state}")self.notify()类观察者(ABC):@abstractmethoddefupdate(self,subject:Subject):passclassConcreteObserverA(Observer):defupdate(self,subject:Subject):ifsubject._state<3:print("ConcreteObserverA:Reactedtotheevent")类ConcreteObserverB(Observer):defupdate(self,subject:Subject):ifsubject._state==0或subject._state>=2:print("ConcreteObserverB:Reactedtotheevent")if__name__=="__main__":subject=ConcreteSubject()observer_a=ConcreteObserverA()subject.attach(observer_a)observer_b=ConcreteObserverB()主题.attach(observer_b)subject.some_business_logic()subject.some_business_logic()subject.detach(observer_a)subject.some_business_logic()结构型外部视图模型外部视图模型提供了一个简单但有限的界面来平面的下降应用复杂性外观模式可以“屏蔽”具有许多活动部件的复杂子系统。使用场景。我创建了外观类,以防我必须使用复杂的库和API和/或我只需要它们的一些功能。?系统复杂度与代码分离?使用门面模式,可以创建一个上帝对象。结构展示示例代码class加法:def__init__(self,field1:int,field2:int):self.field1=field1self.field2=field2defget_result(self):returnself.field1+self.field2class乘法:def__init__(self,field1:int,field2:int):self.field1=field1self.field2=field2defget_result(self):returnself.field1*self.field2class减法:def__init__(self,field1:int,field2:int):self.field1=field1self.field2=field2defget_result(self):returnself.field1-self.field2类Facade:@staticmethoddefmake_addition(*args)->Addition:returnAddition(*args)@staticmethoddefmake_multiplication(*args)->乘法:返回乘法(*args)@staticmethoddefmake_subtraction(*args)->减法:如果__name__则返回减法(*args)=="__main__":addition_obj=Facade.make_addition(5,5)multiplication_obj=Facade.make_multiplication(5,2)subtraction_obj=Facade.make_subtraction(15,5)print(addition_obj.get_result())print(multiplication_obj.get_result())print(subtraction_obj.get_result())装饰器模式装饰器在不修改对象结构的情况下将新行为附加到对象该模式生成一个装饰器类来包装原始类并添加新功能。要使用的场景。每当我需要在不编写代码的情况下向对象添加额外的行为时,我都会使用装饰器模式。?在不创建子类的情况下改变对象行为。?你可以通过将一个对象包装到多个装饰器中来组合多个行为。?一个特定的装饰器很难从包装器堆栈中移除。结构示例代码classmy_decorator:def__init__(self,func):print("insidemy_decorator.__init__()")func()#证明函数定义完成def__call__(self):print("insidemy_decorator.__init__()")func()#证明函数定义完成def__call__(self):print("insidemy_decorator.__call__()")@my_decoratordefmy_function():print("insidemy_function()")if__name__=="__main__":my_function()Adapterpattern适配器模式充当中间类来连接独立或不兼容接口的函数。使用场景。为了在接口之间建立协作,我使用适配器模式来解决格式不兼容问题。例如,适配器可以帮助将XML数据格式转换为JSON以供进一步分析。?允许接口与业务逻辑分离。?添加新适配器不会破坏客户端代码?增加代码复杂度结构示例代码类Target:defrequest(self):return"Target:Thedefaulttarget'sbehavior."Adaptee类:defspecific_request(self):返回“.eetpadAehtforoivaheblaicepS”1]}"defclient_code(target:"Target"):print(target.request())if__name__=="__main__":print("Client:IcanworkjustfinewiththeTargetobjects:")target=Target()client_code(target)adaptee=Adaptee()print("Client:Adaptee类有一个奇怪的接口。""看,我不明白:")print(f"Adaptee:{adaptee.specific_request()}")print("Client:ButIcanworkwithitviatheAdapter:")adapter=Adapter()client_code(adapter)创造性的单例模式单例模式限制一个类有多个实例,并保证实例的全局访问点。使用场景。单例模式帮助我管理共享资源:即由应用程序的多个部分共享的单个数据库、文件管理器或打印机后台处理程序。存储全局状态(帮助文件路径、用户语言、应用程序路径等)。创建一个简单的记录器。?一个类只有一个实例?很难对代码进行单元测试,因为大多数测试框架在创建模拟对象时都使用继承。结构代码示例classSingleton:def__new__(cls):ifnothasattr(cls,'instance'):cls.instance=super(Singleton,cls).__new__(cls)returncls.instanceif__name__=="__main__":s=Singleton()print("Objectcreated:",s)s1=Singleton()print("Objectcreated:",s1)何时使用Python设计模式?当您需要为多个API选项提供统一接口时,外观模式很有用。例如,您应该在应用程序中集成一个支付系统,并保留更改它的可能性。在这种情况下,你可以使用外观模式,你只需要创建一个新的外观,而不需要重写整个应用程序。如果API完全不同,就会出现这里的问题,因为为门面模式设计一个通用的接口并不是一件容易的事。如果初始架构意味着它们的独立性,则状态用于管理应用程序的多个独立组件。因此,为状态管理创建一个单独的模块并使用观察者模式可能是个好主意。由于对装饰器的内置支持,装饰器可能是最常用的Python模式。例如,装饰器提供了一种方便且明确的方式来使用某些库,并为应用程序设计和管理创造了越来越丰富的机会。该模式还确保了函数组合的广泛可能性,并揭示了函数式编程的新机会。适配器适用于处理大量不同格式的数据。这种模式允许一种算法用于每种数据格式,而不是多种算法。迭代器有类似的好处,所以它们可以一起使用。此外,称为生成器的迭代器变体之一(很久以前在Python中引入)允许更有效地使用内存,这对于某些类型的项目在处理大量数据时非常有价值。最后,单例模式的重要性不可低估:数据库连接、API、文件……这些都是开发者应该清楚流程如何避免错误的时刻。而单例模式在这里可以做得很好,更不用说每次都使用同一个实例而不是复制它来减少内存消耗的可能性。翻译顶级设计模式在Python中的实现