当前位置: 首页 > 科技观察

如何理解这6种常见的设计模式?

时间:2023-03-16 01:36:24 科技观察

设计模式可以帮助我们优化代码结构,让代码更加优雅灵活。常见的设计模式有哪些?如何合理使用它们?本文分享作者对工厂模式、单例模式、装饰模式、策略模式、代理模式和观察者模式的理解,并介绍每种模式的模式结构、优缺点、适用场景,注意实现和代码实现.一、前言最近在改造一些历史代码,发现一个明显的特点。大部分代码都是叙述性的,根据事件的发展过程,对故事进行了深入浅出的讲解。这种方法的优点是更符合人的思维习惯。讲完一条主线,代码也不是太难读,只要顺藤摸瓜就能摸到瓜,但缺点也很明显。一旦需要插入一些新的元素,比如:增加一个新的角色,一个新的时间线,就会需要对故事情节进行大量的改动来匹配这个新元素的融入,甚至会对原文章造成破坏性的影响。为了解决这个问题,人们总结出很多种文章结构,如:总分结构、并列结构、总分总分结构等。有了这些结构,在添加新元素时,甚至不需要考虑新的元素和原剧情的衔接,拉个支线独立讲就好,只要能在整体剧情结束前收敛到主线即可(是不是很像git?).在软件开发领域,也有很多这样非常实用的实用总结,我们称之为设计模式。每个人都熟悉设计模式。找个人的话,可以说出N种设计模式,但是除了这些设计模式的概念,很多人并不知道如何灵活的使用这些设计模式。所以就带着这篇文章和大家一起学习一下设计模式的思想吧。2.理解设计模式我尽量用最通俗易懂的例子和语言来描述我所理解的设计模式,希望对大家有所帮助。另外,也没有必要精通所有的设计模式,只要能整合常用的设计模式,就能让你的代码优雅起来。就好比只会三招的程咬金,熟练度无人能及,还能横行天下。1工厂模式(Factory)简单工厂(SimpleFactory)小明追妹妹的时候,给她买了很多咖啡。她喜欢喝卡布奇诺。每次去咖啡店,她只是对服务员说,“来杯卡布奇诺。”“不”就够了。虽然每个公司的口味有些不同,但不管是星爸爸还是歌诗达,都可以提供卡布奇诺咖啡。这里的StarPapa和Costa是生产咖啡的工厂。(1)简单工厂模式结构简单工厂模式包括以下角色:Factory:工厂角色——负责实现创建所有实例的内部逻辑。Product:抽象产品角色——是创建的所有对象的父类,负责描述所有实例。公共接口。ConcreteProduct:具体产品角色——是创建目标,所有创建的对象都作为这个角色的特定类的实例。结构图:时序图:(2)优缺点优点:客户类和工厂类是分开的。每当消费者需要某种产品时,他只需要向工厂提出要求即可。消费者接受未经修改的新产品。缺点:产品修改时,工厂类也必须做相应的修改。工厂方法(FactoryMethod)过去常常带妻子去优衣库(简单工厂)买衣服。款式就这么多,买多了她就烦了。后来,我改变了策略,带老婆去了shoppingmall(抽象工厂),那里有各种品牌的店,没有我她可以逛一整天。与简单工厂不同,核心工厂类(商城)不再负责所有商品的创建,而是将具体的创建工作交给子类(服装店)去做,成为抽象工厂角色,只负责用于给特定工厂类必须实现的接口(store),而不触及应该实例化哪个产品类的细节。(一)工厂方法模式结构工厂方法模式包括以下角色:Product:抽象产品ConcreteProduct:具体产品Factory:抽象工厂ConcreteFactory:具体工厂结构图:时序图:工厂模式总结(一)适用场景输出的产品是标准产品,任何人都可以做到。(2)比如常见的数据库连接工厂,SqlSessionFactory,产品是数据库连接,至于是oracle提供的还是mysql提供的,我不用关心,因为它可以让我通过sql来操作数据。(3)注意事项在项目初期,当软件结构和需求还不稳定时,不建议使用这种模式,因为它的缺点也很明显,增加了代码的复杂度,增加了调用层级,并增加了记忆负担。所以要注意防止滥用模式。(4)packageFactoryMethod的简单实现;publicclassFactoryPattern{publicstaticvoidmain(String[]args){Factoryfactory=newConcreteFactoryA();Productproduct=factory.createProduct();product.use();}}//抽象产品:提供产品接口interfaceProduct{publicvoiduse();}//具体产品A:实现抽象产品classConcreteProductAimplementsProduct中的抽象方法{publicvoiduse(){System.out.println("具体产品A显示...");}}//具体产品B:实现抽象方法中theabstractproductclassConcreteProductBimplementsProduct{publicvoiduse(){System.out.println("具体产品B显示...");}}//抽象工厂:提供生成工厂产品的方法interfaceFactory{publicProductcreateProduct();}//具体工厂A:实现生成工厂产品的方法classConcreteFactoryAimplementsAbstractFactory{publicProductcreateProduct(){System.out.println("具体工厂A生成-->具体产品A。");returnnewConcreteProductA();}}//具体工厂B:实现了产品生成方法classConcreteFactoryBimplementsAbstractFactory{publicProductcreateProduct(){System.out.println("具体工厂B生成-->具体产品B。");returnnewConcreteProductB();}}2单例模式(Singleton)韦小宝有7个妻子,但每个人只有一个丈夫。他所有的妻子都叫老公的时候,都是指他,他是个独例。单例模式结构单例模式包括以下角色:单例:单例结构图:时序图:优缺点优点:全局只有一个实例,便于统一控制,减少系统资源开销。缺点:没有抽象层,难以扩展。应用场景适用于需要全球统一控制的场景,例如全球唯一的代码生成器。注意:对外只提供了公共的getInstance方法,没有提供公共的构造函数。publicclassSingleton的简单实现{privatestaticvolatileSingletoninstance=null;//确保实例在所有线程中同步privateSingleton(){}//private防止类被外部实例化publicstaticsynchronizedSingletongetInstance(){//添加同步if(instance==null)在getInstance方法之前{instance=newSingleton();}returninstance;}}3装饰者模式(Decorator)大学毕业后,如果想给室友送个纪念礼物,可以找一张大家的合影,写上“兄弟永远!”,然后拿到礼品店,放上相框,再用礼盒包装。我和这里的礼品店都是装饰师,都没有改变照片本身,但都让它更适合送礼。装饰模式结构装饰模式包括以下角色:Component:抽象组件ConcreteComponent:具体组件Decorator:抽象装饰类ConcreteDecorator:具体装饰类结构图:序列图:优缺点优点:比继承更灵活(继承是一种高度耦合的静态关系),可以动态地给对象添加职责,并且可以在不影响对象本身的情况下,通过使用不同的装饰器组合为对象扩展N个新功能。缺点:当一个对象的装饰器过多时,会产生很多装饰小对象和装饰组合策略,会增加系统的复杂度,增加阅读和理解代码的成本。适用场景适用于对象功能可以动态增减的场景(通过配置,如:diamond)。适用于一个对象需要N种功能安排的场景(如果使用继承,子类数量会爆炸)。请注意,装饰类的接口必须与装饰类的接口相同。对于client来说,无论是装饰前的对象还是装饰后的对象都可以一视同仁。尽量让具体的组件类Component保持为“轻”类,也就是说,不要在具体的组件类中放入过多的逻辑和状态,可以使用装饰类。packagedecorator的简单实现;publicclassDecoratorPattern{publicstaticvoidmain(String[]args){Componentcomponent=newConcreteComponent();component.operation();System.out.println("------------------------------");Componentdecorator=newConcreteDecorator(component);decorator.operation();}}//抽象组件角色interfaceComponent{publicvoidoperation();}//具体组件角色classConcreteComponentimplementsComponent{publicConcreteComponent(){System.out.println("创建特定组件角色");}publicvoidoperation(){System.out.println("调用特定组件角色的方法operation()");}}//抽象装饰角色classDecoratorimplementsComponent{privateComponentcomponent;publicDecorator(Componentcomponent){this.component=component;}publicvoidoperation(){component.operation();}}//具体装饰角色classConcreteDecoratorextendsDecorator{publicConcreteDecorator(Componentcomponent){super(component);}publicvoidoperation(){super.operation();addBehavior();}publicvoidaddBehavior(){System.out.println("为特定组件角色添加附加函数addBehavior()");}}4策略模式(Strategy)男生追女生一般都会用到这个模式。常见的策略包括:晚餐约会;在看电影;看音乐会;购物;但是可以互相替换,唯一目的就是俘获少女心Strategy模式结构Context:Environment类Strategy:抽象策略类ConcreteStrategy:具体策略类Structuraldiagram:Sequencediagram:AdvantagesanddisadvantagesAdvantages:策略模式提供《开闭原则》完美支持,用户可以在不修改原有系统的情况下选择算法或行为。摆脱复杂丑陋的if-else。缺点:调用时必须提前知道有哪些策略模式类可用,TrialScenario一个系统需要动态地选择几种备选算法中的一种,我们不希望用户关心算法的细节,将具体的算法封装到策略中class.注意事项一定要在strat的注释中描述策略的目的和适用场景埃格班。packagestrategy的简单实现;publicclassStrategyPattern{publicstaticvoidmain(String[]args){Contextcontext=newContext();StrategystrategyA=newConcreteStrategyA();context.setStrategy(strategyA);context.algorithm();System.out.println("----------------");StrategystrategyB=newConcreteStrategyB();context.setStrategy(strategyB);context.algorithm();}}//抽象策略类interfaceStrategy{publicvoidalgorithm();//策略方法}//具体策略类AclassConcreteStrategyAimplementsStrategy{publicvoidalgorithm(){System.out.println("访问具体策略A的策略方法!");}}//具体策略类BclassConcreteStrategyBimplementsStrategy{publicvoidalgorithm(){System.out.println("访问具体策略B的策略方法!");}}//环境类classContext{privateStrategystrategy;publicStrategygetStrategy(){returnstrategy;}publicvoidsetStrategy(Strategystrategy){this.strategy=strategy;}publicvoidalgorithm(){strategy.algorithm();}}5代理模式(Proxy)淘宝店铺客服总是收到很多重复的问题,比如:有货吗?什么时候发货?什么快递?回答一大堆重复的问题太烦人了,于是小米机器人出现了,他来帮客服解答那些已知的问题,遇到小米答不上来的问题就求助于人工客服。这里的小米机器人是客服代理。代理模式结构代理模式包括以下角色:Subject:抽象主体角色Proxy:代理主体角色RealSubject:真实主体角色系统的程度。根据不同的代理类型和场景,进行安全控制,降低系统开销。缺点:增加了一层代理处理,增加了系统的复杂度,可能会降低系统相应的速度。试用场景理论上可以代理任何对象。常见的代理模式有:远程代理:为位于不同地址空间的对象提供本地代理对象。这个不同的地址空间可以在同一台主机上,也可以在另一台主机上,远程代理也称为大使(Ambassador)。虚拟(Virtual)代理:如果需要创建一个消耗大量资源的对象,先创建一个比较小的对象来代表它,真正的对象只有在需要的时候才会创建。Copy-on-Write代理:是一种虚拟代理,将复制(克隆)操作延迟到客户端真正需要它时才执行。一般来说,对象的深度克隆是一项昂贵的操作。Copy-on-Write代理可以延迟这个操作,对象只有在使用的时候才被克隆。保护(ProtectorAccess)代理:控制对一个对象的访问,可以为不同的用户提供不同级别的使用权限。缓存代理:为某个目标操作的结果提供临时存储空间,让多个客户端共享这些结果。防火墙代理:保护目标免受恶意用户的攻击。同步(Synchronization)代理:使多个用户可以同时使用一个对象而不会发生冲突。智能引用(SmartReference)代理:当一个对象被引用时,它提供一些额外的操作,比如记录这个对象被调用的次数等。packageproxy的简单实现;publicclassProxyPattern{publicstaticvoidmain(String[]args){Proxyproxy=newProxy();proxy.request();}}//抽象主题interfaceSubject{voidrequest();}//真实主题classRealSubjectimplementsSubject{publicvoidrequest(){System.out.println("访问真实主题方法...");}}//代理类ProxyiimplementsSubject{privateRealSubjectrealSubject;publicvoidrequest(){if(realSubject==null){realSubject=newRealSubject();}preRequest();realSubject.request();afterRequest();}publicvoidpreRequest(){System.out.println("访问真实主题前的预处理。");}publicvoidafterRequest(){System.out.println("访问真实主题后的后续处理.");}}6观察者模式(Observer)出差在外,想了解一下家里孩子的情况。这时候只要加入“一家人相亲相爱”群,父母经常会把孩子的照片和视频发到群里,你要做的只是一个旁观者,一切都懂刷过群里的信息。观察者模式结构观察者模式包括以下角色:Subject:TargetConcreteSubject:具体目标Observer:观察者ConcreteObserver:具体观察者按照自己的逻辑发送消息,不关心谁消费消息。每个观察者只处理他关心的内容。逻辑相互隔离,带来简洁干净的代码结构。缺点:当观察者很多时,发送一条消息可能会消耗一定的开销,但这条消息可能只会被一个观察者消费。适用场景适用于一对多的业务场景,其中一个对象的变化会触发N个对象做相应的处理。例如:订单调度通知、任务状态变化等。注意事项避免在观察者和被观察者之间形成循环依赖,可能导致系统崩溃。简单的实现packageobserver;importjava.util.*;publicclassObserverPattern{publicstaticvoidmain(String[]args){Subjectsubject=newConcreteSubject();ObserverobsA=newConcreteObserverA();Observerobsb=newConcreteObserverB();subject.add(obsA);subject.add(obsB);subject.setState(0);}}//抽象目标abstractclassSubject{protectedListobserverList=newArrayList();//添加观察者方法publicvoidadd(Observerobserver){observers.add(observer);}//删除观察者方法publicvoidremove(Observerobserver){observers.remove(observer);}publicabstractvoidnotify();//通知观察者方法}//具体目标classConcreteSubjectextendsSubject{privateIntegerstate;publicvoidsetState(Integerstate){this.state=state;//状态变化通知观察者notify();}publicvoidnotify(){System.out.println("具体目标状态变化...");System.out.println("---------------");for(Observerobs:observers){obs.process();}}}//抽象观察者interfaceObserver{voidprocess();//具体processing}//具体观察者AclassConcreteObserverAimplementsObserver{publicvoidprocess(){System.out.println("具体观察者A处理!");}}//具体观察者BclassConcreteObserverBimplementsObserver{publicvoidprocess(){System.out.println("具体观察者B处理!");}}【本文为专栏作者“阿里巴巴官方技术》原创稿件,转载请联系原作者】点此查看作者更多好文