美文网首页Java设计模式随笔-生活工作点滴
大牛分享的几种设计模式及知识要点(完)

大牛分享的几种设计模式及知识要点(完)

作者: 编辑小猿 | 来源:发表于2019-07-10 20:27 被阅读11次

    一、访问者模式(Visitor Pattern )

    定义:Represent an operation to be performed on the elements of an object

    structure. Visitor lets you define a new operation without changing the classes of

    the elements on which it operates. (封装一些作用于某种数据结构中的各元素的

    操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。)

    ● Visitor——抽象访问者

    抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是 visit 方法的

    参数定义哪些对象是可以被访问的。

    ● ConcreteVisitor——具体访问者

    它影响访问者访问到一个类后该怎么干,要做什么事情。

    ● Element——抽象元素

    接口或者抽象类,声明接受哪一类访问者访问,程序上是通过 accept 方法中的参

    数来定义的。

    ● ConcreteElement——具体元素

    实现 accept 方法,通常是 visitor.visit(this),基本上都形成了一种模式了。

    ● ObjectStruture——结构对象

    元素产生者,一般容纳在多个不同类、不同接口的容器,如 List、Set、Map 等,

    在项目中,一般很少抽象出这个角色。

    使用场景:

    ● 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些

    依赖于其具体类的操作,也就说是用迭代器模式已经不能胜任的情景。

    ● 需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这

    些操作“污染”这些对象的类。

    文末福利:kx33389,加她就能免费领取分布式、微服务、源码分析、性能优化、高并发高可用等技术的资料

    二、状态模式(复杂)

    定义:Allow an object to alter its behavior when its internal state changes.The

    object will appear to change its class.(当一个对象内在状态改变时允许其改变行

    为,这个对象看起来像改变了其类。)

    ● State——抽象状态角色

    接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换。

    ● ConcreteState——具体状态角色

    每一个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理,通俗地

    说,就是本状态下要做的事情,以及本状态如何过渡到其他状态。

    ● Context——环境角色

    定义客户端需要的接口,并且负责具体状态的切换。

    使用场景:

    ● 行为随状态改变而改变的场景

    这也是状态模式的根本出发点,例如权限设计,人员的状态不同即使执行相同的行

    为结果也会不同,在这种情况下需要考虑使用状态模式。

    ● 条件、分支判断语句的替代者

    注意:

    状态模式适用于当某个对象在它的状态发生改变时,它的行为也随着发生比较大的

    变化,也就是说在行为受状态约束的情况下可以使用状态模式,而且使用时对象的

    状态最好不要超过 5 个。

    文末福利:kx33389,加她就能免费领取分布式、微服务、源码分析、性能优化、高并发高可用等技术的资料

    三、解释器模式(Interpreter Pattern )(少用)

    定义:Given a language, define a representation for its grammar along with an

    interpreter that uses the representation to interpret sentences in the language.

    (给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该

    表示来解释语言中的句子。)

    ● AbstractExpression——抽象解释器

    具体的解释任务由各个实现类完成,具体的解释器分别由 TerminalExpression 和

    Non-terminalExpression 完成。

    ● TerminalExpression——终结符表达式

    实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表

    达式,但有多个实例,对应不同的终结符。具体到我们例子就是 VarExpression

    类,表达式中的每个终结符都在栈中产生了一个 VarExpression 对象。

    ● NonterminalExpression——非终结符表达式

    文法中的每条规则对应于一个非终结表达式,具体到我们的例子就是加减法规则分

    别对应到 AddExpression 和 SubExpression 两个类。非终结符表达式根据逻辑的

    复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。

    ● Context——环境角色

    具体到我们的例子中是采用 HashMap 代替。

    使用场景:

    ● 重复发生的问题可以使用解释器模式

    ● 一个简单语法需要解释的场景

    注意:

    尽量不要在重要的模块中使用解释器模式,否则维护会是一个很大的问题。在项目

    中可以使用 shell、JRuby、Groovy 等脚本语言来代替解释器模式,弥补 Java 编

    译型语言的不足。

    文末福利:kx33389,加她就能免费领取分布式、微服务、源码分析、性能优化、高并发高可用等技术的资料

    四、享元模式(Flyweight Pattern )

    定义:Use sharing to support large numbers of fine-grained objects efficiently.

    (使用共享对象可有效地支持大量的细粒度的对象。)

    对象的信息分为两个部分:内部状态(intrinsic)与外部状态(extrinsic)。

    ● 内部状态

    内部状态是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改

    变。

    ● 外部状态

    外部状态是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状

    态。

    ● Flyweight——抽象享元角色

    它简单地说就是一个产品的抽象类,同时定义出对象的外部状态和内部状态的接口

    或实现。

    ● ConcreteFlyweight——具体享元角色

    具体的一个产品类,实现抽象角色定义的业务。该角色中需要注意的是内部状态处

    理应该与环境无关,不应该出现一个操作改变了内部状态,同时修改了外部状态,

    这是绝对不允许的。

    ● unsharedConcreteFlyweight——不可共享的享元角色

    不存在外部状态或者安全要求(如线程安全)不能够使用共享技术的对象,该对象

    一般不会出现在享元工厂中。

    ● FlyweightFactory——享元工厂

    职责非常简单,就是构造一个池容器,同时提供从池中获得对象的方法。

    享元工厂的代码:

    public class FlyweightFactory {

    //定义一个池容器

    private static HashMap pool= new

    HashMap();

    //享元工厂

    public static Flyweight getFlyweight(String Extrinsic){

    //需要返回的对象

    Flyweight flyweight = null;

    //在池中没有该对象

    if(pool.containsKey(Extrinsic)){

    flyweight = pool.get(Extrinsic);

    }else{

    //根据外部状态创建享元对象

    flyweight = new ConcreteFlyweight1(Extrinsic);

    //放置到池中

    pool.put(Extrinsic, flyweight);

    }

    return flyweight;

    }

    }

    使用场景:

    ● 系统中存在大量的相似对象。

    ● 细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对

    象没有特定身份。

    ● 需要缓冲池的场景。

    注意:

    ● 享元模式是线程不安全的,只有依靠经验,在需要的地方考虑一下线程安全,在

    大部分场景下不用考虑。对象池中的享元对象尽量多,多到足够满足为止。

    ● 性能安全:外部状态最好以 java 的基本类型作为标志,如 String,int,可以提

    高效率。

    文末福利:kx33389,加她就能免费领取分布式、微服务、源码分析、性能优化、高并发高可用等技术的资料

    五、桥梁模式(Bridge Pattern )

    定义:Decouple an abstraction from its implementation so that the two can vary

    independently.(将抽象和实现解耦,使得两者可以独立地变化。)

    ● Abstraction——抽象化角色

    它的主要职责是定义出该角色的行为,同时保存一个对实现化角色的引用,该角色

    一般是抽象类。

    ● Implementor——实现化角色

    它是接口或者抽象类,定义角色必需的行为和属性。

    ● RefinedAbstraction——修正抽象化角色

    它引用实现化角色对抽象化角色进行修正。

    ● ConcreteImplementor——具体实现化角色

    它实现接口或抽象类定义的方法和属性。

    使用场景:

    ● 不希望或不适用使用继承的场景

    ● 接口或抽象类不稳定的场景

    ● 重用性要求较高的场景

    注意:

    发现类的继承有 N 层时,可以考虑使用桥梁模式。桥梁模式主要考虑如何拆分抽

    象和实现。

    设计原则:

    ●Single Responsibility Principle :单一职责原则

    单一职责原则有什么好处:

    ● 类的复杂性降低,实现什么职责都有清晰明确的定义;

    ● 可读性提高,复杂性降低,那当然可读性提高了;

    ● 可维护性提高,可读性提高,那当然更容易维护了;

    ●变更引起的风险降低,变更是必不可少的,如果接口的单一职责做得好,一个接

    口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护

    性都有非常大的帮助。

    ps:接口一定要做到单一职责,类的设计尽量做到只有一个原因引起变化。

    单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口

    或类设计得是否优良,但是“职责”和“变化原因”都是不可度量的,因项目而异,因

    环境而异。

    ● Liskov Substitution Principle :里氏替换原则

    定义:Functions that use pointers or references to base classes must be able to

    use objects of derived classes without knowing it.

    (所有引用基类的地方必须能透明地使用其子类的对象。)

    通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任

    何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不

    行了,有子类出现的地方,父类未必就能适应。

    定义中包含的四层含义:

    1. 子类必须完全实现父类的方法

    2. 子类可以有自己的个性

    3. 覆盖或实现父类的方法时输入参数可以被放大

    如果父类的输入参数类型大于子类的输入参数类型,会出现父类存在的地

    方,子类未必会存在,因为一旦把子类作为参数传入,调用者很可能进入子类的方

    法范畴。

    4. 覆写或实现父类的方法时输出结果可以被缩小

    父类的一个方法的返回值是一个类型 T,子类的相同方法(重载或覆写)的返

    回值为 S,那么里氏替换原则就要求 S 必须小于等于 T,也就是说,要么 S 和 T

    是同一个类型,要么 S 是 T 的子类。

    ● Interface Segregation Principle:接口隔离原则

    接口分为两种:

    实例接口(Object Interface):Java 中的类也是一种接口

    类接口(Class Interface): Java 中经常使用 Interface 关键字定义的接口

    隔离:建立单一接口,不要建立臃肿庞大的接口;即接口要尽量细化,同时接口中

    的方法要尽量少。

    接口隔离原则与单一职责原则的不同:接口隔离原则与单一职责的审视角度是不相

    同的,单一职责要求的是类和接口职责单一,注重的是职责,这是业务逻辑上的划

    分,而接口隔离原则要求接口的方法尽量少。

    ● Dependence Inversion Principle :依赖倒置原则

    原始定义:

    ①高层模块不应该依赖低层模块,两者都应该依赖其抽象;

    ②抽象不应该依赖细节(实现类);

    ③细节应该依赖抽象。

    依赖倒置原则在 java 语言中的体现:

    ①模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是

    通过接口或抽象类产生的;

    ②接口或抽象类不依赖于实现类;

    ③实现类依赖接口或抽象类。

    依赖的三种写法:

    ①构造函数传递依赖对象(构造函数注入)

    ②Setter 方法传递依赖对象(setter 依赖注入)

    ③接口声明依赖对象(接口注入)

    使用原则:

    依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独

    立,不互相影响,实现模块间的松耦合,我们怎么在项目中使用这个规则呢?只要

    遵循以下的几个规则就可以:

    ①每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备

    ②变量的表面类型尽量是接口或者是抽象类

    ③任何类都不应该从具体类派生(只要不超过两层的继承是可以忍受的)

    ④尽量不要复写基类的方法

    ⑤结合里氏替换原则使用

    ●Open Closed Principle :开闭原则

    定义:软件实体应该对扩展开放,对修改关闭。

    其含义是说一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来

    实现变化。

    软件实体:项目或软件产品中按照一定的逻辑规则划分的模块、抽象和类、方法。

    变化的三种类型:

    ①逻辑变化

    只变化一个逻辑,而不涉及其他模块,比如原有的一个算法是 a*b+c,现在需要修

    改为 a*b*c,可以通过修改原有类中的方法的方式来完成,前提条件是所有依赖或

    关联类都按照相同的逻辑处理。

    ②子模块变化

    一个模块变化,会对其他的模块产生影响,特别是一个低层次的模块变化必然引起

    高层模块的变化,因此在通过扩展完成变化时,高层次的模块修改是必然的。

    ③可见视图变化

    可见视图是提供给客户使用的界面,如 JSP 程序、Swing 界面等,该部分的变化

    一般会引起连锁反应(特别是在国内做项目,做欧美的外包项目一般不会影响太

    大)。可以通过扩展来完成变化,这要看我们原有的设计是否灵活。

    文末福利:kx33389,加她就能免费领取分布式、微服务、源码分析、性能优化、高并发高可用等技术的资料

    粉丝福利

    给大家免费分享一套阿里架构师传授的一套教学资源。帮助大家在成为架构师的道路上披荆斩棘。

    这套视频课程详细讲解了(Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构)等这些成为架构师必备的内容!

    而且还把框架需要用到的各种程序进行了打包,根据基础视频可以让你轻松搭建分布式框架环境,像在企业生产环境一样进行学习和实践。

    关注作者

    码字不易,给作者点个赞

    相关文章

      网友评论

        本文标题:大牛分享的几种设计模式及知识要点(完)

        本文链接:https://www.haomeiwen.com/subject/gmpkkctx.html