程序架构设计
本章主要讲解程序设计的设计模式,开发代码过程中代码质量很重要的,包括健壮性、可维护、可扩展、可替换复用等等,比如:开闭原则(对扩展开放,对修改关闭,在不修改现有代码的前提下对程序进行扩展)等等。所以什么场景采用什么设计模式是需要考虑从整体权衡。
那么什么是程序的设计模式呢?
专业的解释是:针对软件开发过程中重复发生的问题的解决方式方法。
因为设计模式并不是万能公式,也不可滥用,归其根本它是解决什么已明确的问题。
工作应用中也不会像查字典一样找哪种设计模式,而是根据场景和问题进行具体设计,有的并不一定对应着GoF那23种,有的也并不仅是单一模式。
模式很多,并不能一一背下来,需要总结一下,归纳一下供参考,希望能帮助到大家。
功能适应设计模式:
Iterator模式——一个一个遍历
分为Iterator对应ConreteIterator,Aggregate对应ConcreteAggregate两种组合角色
很多jdk原生数据结构中有使用到,比如数组链表实现Iterator接口进行迭代遍历方式,其中还涉及到Composite模式、visitor模式、factory Method模式,后面会总结到。
adapter模式——加个适配器进行复用
也被称为wrapper包装器,或者converter类转换器,为了解决需要使用的程序跟现有的程序的差异问题,对类进行继承、用对象进行委托。Client、Target、Adapter、Adaptee四种角色关系。
将Adaptee转换成Target,适用于连接不同的API,填补缝隙或者差异。
交给子类,实现层次化,可扩展
Template Method——将具体处理交给子类
模板方法很好理解,在父类中定义处理流程框架,在子类中实现具体处理,分为AbstractClass、ConcreteClass两种角色,具有一致性和相互协作。在开发工作流引擎上有很适合的采用。
Factory Method——将实例生成交给子类
通过Template Method模式 来构建生成实例的工厂称为Factory Method模式,它是模板的实现。角色分类creator对应product、ConcreteCreator对应ConcretePorduct,
父类负责生成实例的方式,子类负责生成具体的实例,防止耦合。
生成实例的模式:
spring-ioc创建对象时有用到以下模式,scope进行注解,beanFactory的createBean进行实现。
Singleton——单例,只有一个实例
只存在一个实例,实现方式也分为饿汉懒汉式,具体实现也有很多,懒汉式的实现采用有双检锁、枚举实现等。通常在资源加载方面采用。
prototype——通过复制生成实例
原型模式属对象创建型模式,是拷贝创建对象方式。角色有ConcretePrototype,Prototype,client,拷贝方式又分为深浅拷贝(浅拷贝为对象的内存地址引用,深拷贝可以采用序列化方式实现,以保存对象状态)
说到原型,就会涉及到原型管理器,负责克隆对象的工厂(多个原型存储在集合中)称为原型管理器.
buider——组装复杂实例
将对象所需的各部分组装起来构成实例。角色有Builder、oncreteBuilder、Director。
最常用的插件lombok装饰javaBean类生成builder方法就是采用该模式构建对象。
Abstract Factory——将关联零件组装成产品前面提到Factory Method模式,这里又来个抽象工厂模式,抽象工厂包括工厂,产品两个角色,使用者只关心接口API生成产品,不关心内部零件的封装实现。
分开考虑
bridge——将类的功能层次结构与实现层次结构分离
是一种桥梁,将类的功能层次结构与实现层次结构分离并连接起来;类的功能层次结构是派生类继承适合父类并新增功能;而实现层次结构是子类实现父类的抽象方法,以保证不同类型的任务分配和具体实现,而并非用于增加功能;
所以我们要考虑增加功能还是增加实现,同时将这两部分进行桥接起来建立联系,定义Implementor(实现者)抽象类,Abstraction(抽象化)进行桥接和抽象调用Implementor,RefinedAbstraction(改善后的抽象化)继承Abstraction新增功能,ConcreteImplementor继承Implementor实现具体方法。
strategy——整体替换算法,所谓算法,就是一种策略
意为策略或者算法;为了解决问题,采用了多个解决问题的方式,每个实现方式就是一个策略或者算法,
比如,所熟知的线程池的拒绝策略,服务高可用的选举策略,数据一致性问题解决策略,深度学习中的机器学习策略算法等
一致性
composited——容器与内容一致性
composited为“混合物”的意思,即可表示容器也可表示容器中的具体内容,分为Leaf(树叶)、Composite(复合物)、Component(组件)三个角色;
其实很好理解的,比如:操作系统中的文件、文件夹形式,树的叶子节点和非叶子节点等,都有共同的递归特性。
decorator——装饰与被装饰物的一致性
装饰模式是对事物的特性修饰,分为Component(组件)、concreteComponent、Decorator(装饰物)、ConcreteDecorator(具体的装饰物)角色;在python语法中有种语法糖特性,通过定义装饰器对方法或类进行修饰,而java中通过类似桥接模式中的Abstraction(抽象化)角色来实现装饰者模式做到装饰器效果(实现与桥接模式又很相似)。
访问数据结构
visitor——访问数据结构并处理数据
访问者模式的作用是将数据结构与处理被分离开来;分为visitor、ConcreteVisitor(访问实现者)、Element(元素)、ConcreteElement、ObjectStructure(对象结构);需要数据结构提供访问者访问的入口,访问者提供方法接收数据结构的各元素处理(不过在这里需要注意的是,元素处理交给访问者时,数据结构与访问者的双重分发,类似递归的相互调用,需要检查正确的回退条件,避免死循环产生),一般不建议采用这种模式而让程序变得复杂了。
chain Of Responsibility——推卸责任
在程序设计中解释是“将多个对象组成一条责任链,然后按照它们在职责链上的顺序一个一个地找出到底应该谁来负责处理”;小到类方法,大到架构,专注于所负责的核心,成为可独立复用的组件,避免不同模块之间的功能交叉、职责混乱。它的角色就包括Handler、ConcreteHandler两种,此设计模式在spring、mybatis等开源框架中采用广泛。
简单化
facade——简单单一接口
意为对复杂的程序进行向上抽取,整理形成高层单一API,同时Facade角色会对内部各类之间构建出复杂的责任关系和依赖关系,将复杂的程序演变成层级关系网,并进行单向调用特点,重点是让接口变少了。对程序的执行流程严重依赖主观来判断时,可以考虑采用此角色进行重构。
mediator——只有一个leader
分为四种角色:Mediator(仲裁者)、ConcreteMediator、Colleague(组员)、ConcreteColleague;不同与facade模式,mediator模式是双向调用,
组员向仲裁者报告,仲裁者向组员下达指令,组员之间不相互调用。这种场景并不多,会在复杂的类似链路控制系统设计中采用到,看似简单其实很复杂的的。为了加深印象和理解,有空再抽出时间补充个demo吧。
管理状态
observer——发送状态变化通知
称为“观察者模式”,角色有Subject(观察对象)、ConcreteSubject(具体的观察对象)、Observer(观察者)、ConcreteObserver(具体的观察者),当观察对象的状态发生变化时,会通知给观察者;在线程调度中对线程的生命周期监听、MQ中的事件监听 都有采用到,其实该模式体现在被动地接受Subject通知,又称为“发布-订阅(Publish-Subscribe)”模式。
Memento——保存对象状态
“Memento“有”备忘录“的含义,模式为了恢复对象以前保存的状态,同时防止破坏对象原有的封装性。那么这里的实现思路是,单独实现状态类(Memento角色)保存状态生成类(Originator角色)的状态信息,状态类中持有快照方法、撤销方法。
state——用类表示状态
类本来是抽象或者描述事物的,在这里是要用类来表示状态,有点不理解,一般情况下都采用接口属性,或者枚举来表示状态值。在这里类的独特性也是依照类中的属性值或者类对状态进行存储状态信息,从而对类作为状态值 进行比较判断。这里需要注意的地方是,每个具体状态类应该设计为单例模式,并作为数据共享。
避免浪费
flyWeight——对象共享
意为“轻量级”,该模式是为了让对象变得“轻”——减少内存的消耗。不难理解了,通过共享实例来避免new太多实例。这里要跟singleton区分开,flyWeight模式有flyWeight、flyWeightFactory(轻量工厂)两种角色,flyWeightFactory采用singleton生成的,而另一方面,减少new实例是通过存放已生成的少量实例用pool池来存取,从而达到不浪费资源(包括时间和空间)。
proxy——只有必要时生成对象
指代理模式,代替别的实例进行工作的类,为其他对象提供一种代理以控制对这个对象的访问,以及进行某些特定的处理,分为Subject(主体)、Proxy(代理人)、RealSubject(实际的主体)角色。代理也分为静态代理和动态代理;spring中的两种动态代理(jdk代理、cglib代理)底层都是依赖共同的j.l.r.Proxy来实现。下期将对spring的代理作深入源码详解。
用类来表示
Command——命令也是类
所谓“命令也是类”,不再是通过类来进行方法的调用,而是用一个实例来表示命令(包括具体的事件流),同时可以管理和再次执行它们。命令的集合是通过栈来存储的,可以理解为类似程序的方法栈。我想到一个demo后续将添加上去。
interpreter——语法规则也是类
interpreter模式也叫“解释器”,解释器模式是一种语法解释器构架,通过解释文件的语法来运行出效果。就比如训练的模型通过文件来表达,里面包含了算法运算、运算参数等信息,解释器通过解析文件知道怎样进行预处理分析,比如kettle通过解析.ktr执行具体的工作流程。很类似。
设计模式就总结到此,详细再进行补充。