设计模式分类理解

慢慢经过几年项目的历练,特别是对接一些特殊客户的需求,以及对老项目的接手,无时无刻都在遇到各种需求兼容的问题。在遇到这么多的问题后,再来看设计模式,你会有“我靠,原来xxx项目的需求可以这样解决!”的感叹。

并且对于不同的设计模式,自己也具备一定的选择能力。我在经历过一些项目的鞭策[特别是政府类],同时又回顾一下以前学习的设计模式,特意将设计模式的内容大致整理归类一下,将24种设计模式,分别归类到如下三个大类,希望对大家了解设计模式有一些帮助!

第一、创建型模式:创建对象的过程,一般情况下我们创建对象,主要是通过new类进行创建,哪里需要就在哪里创建。后续使用spring框架中,由于引入了spring的容器,有些类的创建就通过注解等方式进行创建和实例化,正在的创建和实例化就交由spring容器,通过反射方式进行创建。但是在实际工作中,会遇到很对奇特的需求,仍然会使用new或者注解等基础方式创建。但这样会导致后续的需求变更中,new出来的对象非常难维护和拓展,会让你不得不面临着修改原有结构的代码,这可能会导致更加致命的问题,因为你不知道你改的这段代码,在某些特殊操作情况下,会不会让程序崩溃?在这样的背景下,各类大神就提出了不同类型的创建对象方式,也就是创建型的设计模式。

创建型模式包括:单例模式原型模式建造者模式工厂模式

单例模式:程序运行中,仅存在一个实例。目前实现方式上有饿汉模式[静态变量初始化]和懒汉模式[方法内初始化],目前在项目也只是在做初始化配置才使用,比如加载微信对接的appid、secret、微信模板的templeId等,目前用途并不大。

         原型模式:通过复制方式,直接创建对象。复制的方式分为深克隆(基本类型和引用类型均克隆)和浅克隆(基本类型克隆)。在历史项目中遇到过克隆方式,情况大致是告警组件采用c++的方式编写,接受方采用java编写,两者通过soap协议进行编写。由于java端接收到传递过来的信息后,需要将告警信息分成多份,一部分需要做业务处理,另一部分需要在转发给上级平台。同时由于告警信息内容较多,对象内的成员变量有十几个,如果用new的方式进行创建,代码多且会分散在每个应用业务中。在这种情况下,前辈们采用了克隆模式,直接复制接收对象,分开成两个业务进行处理。但是由于最初的告警对象内成员变量均为基本类型,因此最初的克隆方式采用浅克隆,后续项目接手过程中,在不知道此情况下,我直接加入一个引用类型对象,导致在上级平台中,无法获取引用对象数据。后来手动改成深克隆解决此问题。

         建造者模式:原始的解释是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。啥意思呢?简单举例子说明。

以上图车辆对象为例,通常情况下如何创建?大多数都是针对轮胎、车体结构、发动机等单独创建类,每个类均有自己的成员变量。再通过创建车辆类,车辆类引用轮胎类、车体结构类、发动机类。当系统中存在奥迪、大众、本田等不同的车辆类时,如何进行区分创建?通常情况下。最后在相应的代码中,需要创建某个车辆对象时,需要先创建轮胎对象、再创建车体结构对象、再创建发动机对象,最后赋值到车辆对象。整个过程中,代码量将变得非常多。

建造者模式中,轮胎类、车体结构类、发动机类、车辆类依旧会创建,另外创建车辆建造接口,并规定此接口中需要实现轮胎类、车体结构、发动机的创建方法。面对不同的车辆时,只需要不断新增车辆建造实现类即可。通过建造类中规定,此类车辆使用某种类型的轮胎、车体结构、发动机。

         实际应用过程中,并没有用到建造者模式,一部分原因是没有碰到三层及以上的对象架构。另外个人觉得建造类对于轮胎等子类非常依赖。

工厂模式:将对象的创建过程交由工厂类进行,或者其子类进行,实现对象创建的解耦功能;如何理解?之前在某个博客中看到描述,个人觉得比较贴切。

简单工厂模式:一个花园,只种花,即花园内有不同的花,花园为一个工厂类,通过不同的花名称或者调用工厂不同方法,返回不同的花对象。

工厂模式:一个花园,种花、树、草等,即设置一个植物接口,花、树、草均实现植物接口,花园为一个工厂类,通过传递不同的参数,返回不同的花、树、草等对象。

抽象工厂模式:多个花园,不同花园有不同种植方案,即需要设置植物接口,花、树、草均实现植物接口,另外还需设置花园接口,不同花园实现工厂接口,如此可保证不同花园有不同的种植方式。

总结:单例模式和原型模式较为简单,此处主要对比工厂模式和建造者模式,工厂模式中,侧重于对每个产品类型的分类,类似于横向比较,而建造者模式中侧重于对某个产品的组成,类似于纵向比较。

 

第二、结构型模式:主要用于改变类或对象的结构,以达到业务场景需要的操作模式,其操作基本是通过继承被操作对象,或者定义被操作对象的变量,从而构造出新对象,并通过继承此新对象来不断衍生新派生对象,以解决需求不断增加新内容的目的,主要包括适配器模式桥接模式组合模式装饰者模式外观模式享元模式代理模式、委派模式

适配器模式:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。简单点理解就是,存在接口a和接口b,由于业务需要,必须要a具备b接口的能力,这时候可以创建一个adapterA接口,用于继承a接口,并且在adapterA接口中申明或继承b接口,这样就可以在adapterA接口的实现类中,直接使用b接口。此模式一般分为类适配和对象适配两种,主要区别在于adapterA是直接继承a、b两个接口(类适配),还是只继承a并申明b的方式(对象适配)。

桥接模式:将抽象部分与它的实现部分分离,使它们都可以独立的变化。包存在类型和颜色的两个维度,类型中包括挎包、背包等,颜色分为红、绿、黄等。采用桥接模式中,申明包类型接口,分别实现挎包类和背包类。在定义颜色抽象类,抽象类中定义包类型接口,并设置该包类型接口的set和get方法,最后通过不同的颜色实现类来继承颜色抽象类,形成完整的业务对象。桥接和适配器的最大区别在于,桥接重点在于业务对象的多维度划分,适配器重点在于对象适配于另一个对象。

组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构。网上看到案例较为精准(https://www.cnblogs.com/lfxiao/p/6816026.html),大致描述内容为需要做一个杀毒软件,由于杀毒对象可以是文件夹、图片、文档等,因此需要在文件夹对象中封装图片、文档等对象的集合,通过对此类集合进行增删操作来控制文件夹内文件数量。如果单独对图片、文档等设置增删,将会有很多重复性的增删代码。因此在组合模式中,将图片、文档等抽象成Component(定义增删改查以及杀毒方法),然后Leaf类实现Component的所有方法(重点在于实现杀毒方法),最后通过Composite容器组件将所有的leaf包含在一起,即具备leaf的集合变量,最后通过Composite统一操作对象。

装饰者模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更灵活。购买手抓饼业务,基础的手抓饼会有一个基础价格,但是随着增加的菜品增加,手抓饼的价格也会增加。通常情况下,我们会创建一个手抓饼对象,然后设置不同菜品的标识变量,在业务中我们会通过判断是否具备菜品标识变量,来进行价格的判定,即使用很多的if来判断。装饰者模式中,我们会通过设置手抓饼的抽象类Component,然后设置手抓饼具体实现类,并定义基础价格ConcreteComponent,在创建装饰者接口类Decorator,接口类中定义变量Component,并通过构造方法引入Component,最后装饰类的实现类ConcreteDecorator通过继承来表示加入不同菜品的手抓饼,最后返回不同的菜品价格。

外观模式:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。在没有实现最多跑一次流程情况下,如果想办理某个业务,需要进行一些审批(approve接口),则需要不断在各单位之间进行审批(approve实现类),但是后来实现最多跑一次,只需要在某个集中点完成审批(ApproveFacade,定义多个approve实现类作为成员变量),则所有流程将全部审批完成。而集中审批点就被称为外观模式的高层接口。

享元模式:运用共享技术有效的支持大量细粒度的对象。目前我在项目中使用最多的情况就是数据字典的存放。系统中将所有的数据字典封装到一个map中,通过key来标识唯一性,这样就算不断重复加入同一个key的数据字典,对于map来说也只有一个。再对此map提供读取的方法,则其他地方只需传递不同的key,就可以获取不同的数据字典。其重点在于创建共享的池,类似string和数据库连接池。

代理模式:为其他对象提供一种代理以控制对这个对象的访问。主要区分与静态代理和动态代理,区别在于是否运行前存在class文件,存在则为静态代理。动态代理的重点是通过反射方式生成代理对象。

 

第三、行为型模式:主要用于对象行为进行抽象的操作,将分散在对象中的行为方法根据不同的业务场景抽象出不同的执行类,再由执行类来实现行为方法,将对象和行为进行解耦,主要包括观察者模式模板方法命令模式状态模式职责链模式解释器模式中介者模式访问者模式策略模式备忘录模式迭代器模式

观察者模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,让它们能够自动更新自己。经典案例是微信公众号,公众号抽象类是被观察者(Observerable),微信公众号是被观察者实现类,即某个集体的被观察者(WechatServer),观察者是微信号的抽象类(Observer),具体某个微信号是观察者实现类(wechat),Observerable中存在Observer的list集合,当WechatServer发送消息时,则每个wechat都将监听到WechatServer发送的消息。

模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。经手的某个项目中,有这样的业务场景,系统中存在一个业务报修的流程,主流程为报修、受理、维修、确认四个步骤,但是每个步骤会针对不同的情况存在不同的数据处理。红绿灯必须由内部人员才能报修、车辆报修必须要求交由业务主任认定未非事故后才可以报修。因此在业务中,定义一个主流程的抽象类,要求流程必须依次经过报修、受理、维修、确认这四个流程,在创建红绿灯报修实现类、车辆报修实现类,分别定义不同的实现方法,最后外部只需调用父类的主流程执行方法即可。

命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。在消息推送模块中曾有类似的情况,每个子模块只需要将消息发送给推送模块,发送后即不理会是否发送成功,将发送的消息封装成对象(存库或者存list),然后提交给消息推送模块,由消息推送模块依次读取消息,然后逐条发送。

状态模式:当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类。目前经常遇到的工单的处理流程,比如有一个维修单,状态包括派单、签收、签到、反馈、确认等流程,通常情况下,我们会设置某个status的标记,通过status的值不同,表示维修单经过不同的行为。但是在状态模式中,抽象除状态的抽象类,抽象类的构造方法中需要将维修单对象实例化,并赋值给保护的变量,并定义状态改变的行为方法。每个状态都是此抽象类的具体实现类,针对不同的状态实现不同的行为方法。这样对于状态的拓展和处理将变成状态类内部事情,有利于将状态操作解耦。

职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。请假的案例中,职员提交的请求将先经过部门经理,在经过副总、总经理审批,最后由人事进行备案。通常的过程中,我们将会在请求的类中,定义部门经理处理方法、副总处理方法、总经理处理方法、人事处理方法。最后在业务中将逐个方法调用。职责链模式中,将抽象出审批抽象类,抽象类中申明处理方法和下一个执行者,每个步骤都是此抽象类的具体实现,每次执行结束都将由指定的下一个执行者进行操作。

解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。经典例子就是计算器,+、-、*、/分别是各类符号,抽象出符号抽象类,+、-、*、/则表示不同的符号实现类,最后定义出解释器的抽象类,根据不同的解释方式对符号进行解析(8进制、10进制、16进制等)。

中介者模式:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示的相互引用,从而使其耦合松散,而且可以独立的改变它们之间的交互。在租房的场景中,当我们需要去租房,可能需要和n个不同类型的人员沟通才能确定房子。在中介者模式中,通过创建中介,中介中初始化每个对象的变量,和业务处理的方法,即每个对象只需关系自己发出的消息和得到的结果,至于消息的处理和转发均有中介完成。

https://i-blog.csdnimg.cn/blog_migrate/90684ba949bc4d786ebd6eb8bf966182.jpeg

访问者模式:表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。财务和人事结算模式案例,职工分为临时工和正式工,由于临时工的工资结算方式(天制)和正式工不同(月制),另外人事统计出勤率也会区分临时工和正式工,通常情况下通过创建结算类,类中包括临时工对象List和正式工对象List,再编写人事结算方法和财务结算方法,这种情况下,代码中if判断较多,且后续中增加另一种结算方式也非常困难。访问者模式中,采用抽象出职工抽象类和访问者抽象类,临时工和正式工分别继承职工抽象类,并引入访问者实现类,用于调用自己的内部数据。财务结算方式和人事结算方式则继承访问者抽象类,并实现自己的结算方式。通过此方式将结算和职工解耦,当需要在增加员工或者结算方式时,只需要新增职工和结算方式的实现类即可。

策略模式:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。此模式是使用最泛的模式,当存在对不同业务需要差异化处理,就可以采用策略模式。通俗来说就是封装一个方法,通过传递的参数不同,调用不同的实现类,已完成差异化处理的业务场景。

备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态。曾经遇到的案例是,有一个工单处理流程,但是客户要求,针对每个步骤都需要做回退操作。由于每个操作都会带来很多字段的调整,如果用if方法逐项回退将变得异常困难,特别是用户还要求需要回退到指定状态下,这样的业务处理将变得非常痛苦。在备忘录模式下,可以直接建立一张临时表作为工单表的备份,当需要回退是,只需要将临时表数据赋值给工单表即可。

迭代器模式:提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。目前开发中,我们应该很少用到此模式,因为迭代器已被java集成到基础类中。

 

MVC模式:集观察者、组合、策略为一体,是多种模式的综合应用,算是一种架构模式。

 

本文引用来源:https://blog.csdn.net/u014282557/article/details/72823201

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值