精华内容
下载资源
问答
  • 它的讲解思路为:模式动机->模式定义->模式结构->模式分析(即原理)->实例解析->模式优缺点->模式使用场景->模式应用->模式扩展。采用图文+文字+实例的方式,让读者不仅知其然,还能知其所以然。读后有种豁然开朗的...
  • 包含Java23中设计模式源码和案例分析源码,适合初学者研究和提升技术水平
  • 主要介绍了Java设计模式模板方法(Template)原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 设计模式书籍--作者刘伟(Sunny)中南大学计算机应用技术博士,国家认证系统分析师(2005年),国家认 证系统架构设计师(2009年,全国第四名),高级程序员,数据库系统工程师,MCSE, MCDBA,CASI专业顾问与企业内训...
  • 主要介绍了java设计模式之委派模式原理分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 主要介绍了Java设计模式 模板模式及应用场景解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 本课程是使用Java来讲解设计模式,考虑到设计模式比较抽象,授课采用 图解+框架源码分析的方式 1) 内容包括: 设计模式七大原则(单一职责、接口隔离、依赖倒转、里氏替换、开闭原则、迪米特法则、合成复用)、UML...
  • 本课程针对上述问题,有针对性的进行了升级 (1) 授课方式采用 图解+框架源码分析的方式,让课程生动有趣好理解 (2) 系统全面的讲解了设计模式,包括 设计模式七大原则、UML类图-类的六大关系、23种设计模式及其分类,...
  • 关于设计模式中涉及的原则与模式,项目使用java编码实现设计模式设计模式 原则 单一职责原则 单一职责原则(SRP),就一个类而言,应该仅有一个引起它变化的原因。 如果一个类承担的职责过多,就等于把这些职责耦合...
  • 主要介绍了Java设计模式之建造者模式,结合具体实例形式分析了建造者模式的概念、原理、实现方法与相关使用注意事项,需要的朋友可以参考下
  • Java设计模式精讲

    2015-02-04 10:44:07
    您是一个初级的 coder,可以从中领会到怎么设计一段优秀的...您是一个高级程序员,可以从中全面了解到设计模式以及 Java 的边角技术的使用;您是一个顶级的系统分析师,可以从中获得共鸣,寻找到项目公共问题的解决办法
  • java设计模式精讲 Debug 方式+内存分析 设计模式是工程师必备知识,也是面试高频考点。这门课程将从设计模式定义、应用到源码解析,带你系统学习设计模式,并结合大量场景 Coding,让学习不枯燥,不空洞。同时采用 ...
  • Java常见设计模式总结

    万次阅读 多人点赞 2021-09-18 17:18:54
    设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式于己于人于系统都是多赢的,它使得代码编写真正工程化,它是软件工程的基石,如同大厦的一块块...

     一、设计模式总述:

    1、什么是设计模式:

            设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 设计模式于己于人于系统都是多赢的,它使得代码编写真正工程化,它是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。总体来说,设计模式分为三大类:

    • 创建型模式:共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
    • 结构型模式:共7种:适配器模式、装饰器模式、代理模式、桥接模式、外观模式、组合模式、享元模式
    • 行为型模式:共11种:策略模式、模板方法模式、观察者模式、责任链模式、访问者模式、中介者模式、迭代器模式、命令模式、状态模式、备忘录模式、解释器模式

    其实还有两类:并发型模式和线程池模式,用一个图片来整体描述一下:

    2、设计模式的六大原则:

    (1)开闭原则 (Open Close Principle) :

            开闭原则指的是对扩展开放,对修改关闭。在对程序进行扩展的时候,不能去修改原有的代码,想要达到这样的效果,我们就需要使用接口或者抽象类

    (2)依赖倒转原则 (Dependence Inversion Principle):

            依赖倒置原则是开闭原则的基础,指的是针对接口编程,依赖于抽象而不依赖于具体

    (3)里氏替换原则 (Liskov Substitution Principle) :

            里氏替换原则是继承与复用的基石,只有当子类可以替换掉基类,且系统的功能不受影响时,基类才能被复用,而子类也能够在基础类上增加新的行为。所以里氏替换原则指的是任何基类可以出现的地方,子类一定可以出现。

            里氏替换原则是对 “开闭原则” 的补充,实现 “开闭原则” 的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏替换原则是对实现抽象化的具体步骤的规范。

    (4)接口隔离原则 (Interface Segregation Principle):

            使用多个隔离的接口,比使用单个接口要好,降低接口之间的耦合度与依赖,方便升级和维护方便

    (5)迪米特原则 (Demeter Principle):

            迪米特原则,也叫最少知道原则,指的是一个类应当尽量减少与其他实体进行相互作用,使得系统功能模块相对独立,降低耦合关系。该原则的初衷是降低类的耦合,虽然可以避免与非直接的类通信,但是要通信,就必然会通过一个“中介”来发生关系,过分的使用迪米特原则,会产生大量的中介和传递类,导致系统复杂度变大,所以采用迪米特法则时要反复权衡,既要做到结构清晰,又要高内聚低耦合。

    (6)合成复用原则 (Composite Reuse Principle):

            尽量使用组合/聚合的方式,而不是使用继承。

    二、Java的23种设计模式:

            接下来我们详细介绍Java中23种设计模式的概念,应用场景等情况,并结合他们的特点及设计模式的原则进行分析

    1、创建型-工厂方法模式:

    工厂方法模式分为三种:

    (1)简单工厂模式:

    建立一个工厂类,并定义一个接口对实现了同一接口的产品类进行创建。首先看下关系图:

    (2)工厂方法模式:

    工厂方法模式是对简单工厂模式的改进,简单工厂的缺陷在于不符合“开闭原则”,每次添加新产品类就需要修改工厂类,不利于系统的扩展维护。而工厂方法将工厂抽象化,并定义一个创建对象的接口。每增加新产品,只需增加该产品以及对应的具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合“开闭原则”了,扩展时不必去修改原来的代码。UML关系图如下:

     (3)静态工厂方法模式:

    静态工厂模式是将工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

    工厂方法模式详情文章:Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)

    2、创建型-抽象工厂模式:

            抽象工厂模式主要用于创建相关对象的家族。当一个产品族中需要被设计在一起工作时,通过抽象工厂模式,能够保证客户端始终只使用同一个产品族中的对象;并且通过隔离具体类的生成,使得客户端不需要明确指定具体生成类;所有的具体工厂都实现了抽象工厂中定义的公共接口,因此只需要改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。

            但该模式的缺点在于添加新的行为时比较麻烦,如果需要添加一个新产品族对象时,需要更改接口及其下所有子类,这必然会带来很大的麻烦。

            UML结构图如下:

    抽象工厂模式详情:Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)

    3、创建型-建造者模式:

             建造者模式将复杂产品的创建步骤分解在在不同的方法中,使得创建过程更加清晰,从而更精确控制复杂对象的产生过程;通过隔离复杂对象的构建与使用,也就是将产品的创建与产品本身分离开来,使得同样的构建过程可以创建不同的对象;并且每个具体建造者都相互独立,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。UML结构图如下:

     建造者模式详情:Java设计模式之创建型:建造者模式

    4、创建型-单例模式:

            单例模式可以确保系统中某个类只有一个实例,该类自行实例化并向整个系统提供这个实例的公共访问点,除了该公共访问点,不能通过其他途径访问该实例。单例模式的优点在于:

    • 系统中只存在一个共用的实例对象,无需频繁创建和销毁对象,节约了系统资源,提高系统的性能
    • 可以严格控制客户怎么样以及何时访问单例对象。

    单例模式的写法有好几种,主要有三种:懒汉式单例、饿汉式单例、登记式单例。

    单例模式详情:Java设计模式之创建型:单例模式

    5、创建型-原型模式:

            原型模式也是用于对象的创建,通过将一个对象作为原型,对其进行复制克隆,产生一个与源对象类似的新对象。UML类图如下:

     在 Java 中,原型模式的核心是就是原型类 Prototype,Prototype 类需要具备以下两个条件:

    • 实现 Cloneable 接口:
    • 重写 Object 类中的 clone() 方法,用于返回对象的拷贝;

    Object 类中的 clone() 方法默认是浅拷贝,如果想要深拷贝对象,则需要在 clone() 方法中自定义自己的复制逻辑。

    • 浅复制:将一个对象复制后,基本数据类型的变量会重新创建,而引用类型指向的还是原对象所指向的内存地址。
    • 深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。

            使用原型模式进行创建对象不仅简化对象的创建步骤,还比 new 方式创建对象的性能要好的多,因为 Object 类的 clone() 方法是一个本地方法,直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显;

    原型模式详情:Java设计模式之创建型:原型模式

            

            上面我们介绍了5种创建型模式,下面我们就开始介绍下7种结构型模式:适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。其中对象的适配器模式是各种模式的起源,如下图:

    6、结构型-适配器模式:

            适配器模式主要用于将一个类或者接口转化成客户端希望的格式,使得原本不兼容的类可以在一起工作,将目标类和适配者类解耦;同时也符合“开闭原则”,可以在不修改原代码的基础上增加新的适配器类;将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性,但是缺点在于更换适配器的实现过程比较复杂。

            所以,适配器模式比较适合以下场景:

    • (1)系统需要使用现有的类,而这些类的接口不符合系统的接口。
    • (2)使用第三方组件,组件接口定义和自己定义的不同,不希望修改自己的接口,但是要使用第三方组件接口的功能。

    下面有个非常形象的例子很好地说明了什么是适配器模式:

    适配器模式的主要实现有三种:类的适配器模式、对象的适配器模式、接口的适配器模式。三者的使用场景如下:

    • 类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
    • 对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。
    • 接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。

    适配器模式详情:Java设计模式之结构型:适配器模式

    7、结构型-装饰器模式:

            装饰器模式可以动态给对象添加一些额外的职责从而实现功能的拓展,在运行时选择不同的装饰器,从而实现不同的行为;比使用继承更加灵活,通过对不同的装饰类进行排列组合,创造出很多不同行为,得到功能更为强大的对象;符合“开闭原则”,被装饰类与装饰类独立变化,用户可以根据需要增加新的装饰类和被装饰类,在使用时再对其进行组合,原有代码无须改变。装饰器模式的UML结构图如下:

            但是装饰器模式也存在缺点,首先会产生很多的小对象,增加了系统的复杂性,第二是排错比较困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

    装饰器模式详情:Java设计模式之结构型:装饰器模式

    8、结构型-代理模式:

            代理模式的设计动机是通过代理对象来访问真实对象,通过建立一个对象代理类,由代理对象控制原对象的引用,从而实现对真实对象的操作。在代理模式中,代理对象主要起到一个中介的作用,用于协调与连接调用者(即客户端)和被调用者(即目标对象),在一定程度上降低了系统的耦合度,同时也保护了目标对象。但缺点是在调用者与被调用者之间增加了代理对象,可能会造成请求的处理速度变慢。UML结构图如下:

    代理模式详情:Java设计模式之结构型:代理模式

    9、结构型-桥接模式:

            桥接模式将系统的抽象部分与实现部分分离解耦,使他们可以独立的变化。为了达到让抽象部分和实现部分独立变化的目的,桥接模式使用组合关系来代替继承关系,抽象部分拥有实现部分的接口对象,从而能够通过这个接口对象来调用具体实现部分的功能。也就是说,桥接模式中的桥接是一个单方向的关系,只能够抽象部分去使用实现部分的对象,而不能反过来。 

            桥接模式符合“开闭原则”,提高了系统的可拓展性,在两个变化维度中任意扩展一个维度,都不需要修改原来的系统;并且实现细节对客户不透明,可以隐藏实现细节。但是由于聚合关系建立在抽象层,要求开发者针对抽象进行编程,这增加系统的理解和设计难度。桥接模式的UML结构图如下:

            就像在Java中我们使用 JDBC 连接数据库时,在各个数据库之间进行切换,基本不需要动太多的代码,原因就是使用了桥接模式,JDBC 提供统一接口,每个数据库提供各自的实现,然后由桥接类创建一个连接数据库的驱动,使用某一个数据库的时候只需要切换一下就行。JDBC 的结构图如下:

             在 JDBC 中,桥接模式的实现化角色 (Implementor) 为的 Driver 接口,具体实现化 (Concrete Implementor) 角色对应 MysqlDriver、OracleDriver 和 MariadbDriver,扩展抽象化 (Refined Abstraction) 角色对应 DriverManager,不具有抽象化 (Abstraction) 角色作为扩展抽象化角色的父类。

    桥接模式详情:Java设计模式之结构型:桥接模式

    10、结构型-外观模式:

            外观模式通过对客户端提供一个统一的接口,用于访问子系统中的一群接口。使用外观模式有以下几点好处:

    (1)更加易用:使得子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要跟众多子系统内部的模块进行交互,只需要跟外观类交互就可以了;

    (2)松散耦合:将客户端与子系统解耦,让子系统内部的模块能更容易扩展和维护。

    (3)更好的划分访问层次:通过合理使用 Facade,可以更好地划分访问的层次,有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到门面中,这样既方便客户端使用,也很好地隐藏了内部的细节。

            但是如果外观模式对子系统类做太多的限制则减少了可变性和灵活性,所以外观模式适用于为复杂子系统提供一个简单接口,提高系统的易用性场景 以及 引入外观模式将子系统与客户端进行解耦,提高子系统的独立性和可移植性。

            外观模式的UML结构图如下:

    外观模式详情: Java设计模式之结构型:外观模式

    11、结构型-组合模式:

            组合模式将叶子对象和容器对象进行递归组合,形成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性,能够像处理叶子对象一样来处理组合对象,无需进行区分,从而使用户程序能够与复杂元素的内部结构进行解耦。

            组合模式最关键的地方是叶子对象和组合对象实现了相同的抽象构建类,它既可表示叶子对象,也可表示容器对象,客户仅仅需要针对这个抽象构建类进行编程,这就是组合模式能够将叶子节点和对象节点进行一致处理的原因。组合模式的UML结构图如下:

    组合模式详情: Java设计模式之结构型:组合模式

    12、结构型-享元模式:

            享元模式通过共享技术有效地支持细粒度、状态变化小的对象复用,当系统中存在有多个相同的对象,那么只共享一份,不必每个都去实例化一个对象,极大地减少系统中对象的数量,从而节省资源。

            享元模式的核心是享元工厂类,享元工厂类维护了一个对象存储池,当客户端需要对象时,首先从享元池中获取,如果享元池中存在对象实例则直接返回,如果享元池中不存在,则创建一个新的享元对象实例返回给用户,并在享元池中保存该新增对象,这点有些单例的意思。

            工厂类通常会使用集合类型来保存对象,如 HashMap、Hashtable、Vector 等等,在 Java 中,数据库连接池、线程池等都是用享元模式的应用。

            享元模式的UML结构图如下:

             Java 中,String 类型就是使用享元模式,String 对象是 final 类型,对象一旦创建就不可改变。而 Java 的字符串常量都是存在字符串常量池中的,JVM 会确保一个字符串常量在常量池中只有一个拷贝。

            而且提到共享池,我们也很容易联想到 Java 里面的JDBC连接池,通过连接池的管理,实现了数据库连接的共享,不需要每一次都重新创建连接,节省了数据库重新创建的开销,提升了系统的性能!

    享元模式详情:Java设计模式之结构型:享元模式

            前面我们介绍了7种结构型设计模式,接下来我们介绍一下11种行为型设计模式:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。先来张图,看看这11中模式的关系:

     13、行为型-策略模式:

            将类中经常改变或者可能改变的部分提取为作为一个抽象策略接口类,然后在类中包含这个对象的实例,这样类实例在运行时就可以随意调用实现了这个接口的类的行为。

            比如定义一系列的算法,把每一个算法封装起来,并且使它们可相互替换,使得算法可独立于使用它的客户而变化,这就是策略模式。UML结构图如下:

            策略模式的优点在于可以动态改变对象的行为;但缺点是会产生很多策略类,并且策略模式的决定权在用户,系统只是提供不同算法的实现,所以客户端必须知道所有的策略类,并自行决定使用哪一个策略类; 

            策略模式适用用于以下几种场景:

    • (1)应用程序需要实现特定的功能服务,而该程序有多种实现方式使用,所以需要动态地在几种算法中选择一种
    • (2)一个类定义了多种行为算法,并且这些行为在类的操作中以多个条件语句的形式出现,就可以将相关的条件分支移入它们各自的Strategy类中以代替这些条件语句。

    策略模式详情:Java设计模式之行为型:策略模式

    14、行为型-模板方法:

            模板方法是基于继承实现的,在抽象父类中声明一个模板方法,并在模板方法中定义算法的执行步骤(即算法骨架)。在模板方法模式中,可以将子类共性的部分放在父类中实现,而特性的部分延迟到子类中实现,只需将特性部分在父类中声明成抽象方法即可,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤,不同的子类可以以不同的方式来实现这些逻辑。

            模板方法模式的优点在于符合“开闭原则”,也能够实现代码复用,将不变的行为转移到父类,去除子类中的重复代码。但是缺点是不同的实现都需要定义一个子类,导致类的个数的增加使得系统更加庞大,设计更加抽象。模板方法模式的UML图如下:

    模板方法详情:Java设计模式之行为型:模板方法模式

    15、行为型-责任链模式:

            职责链可以将请求的处理者组织成一条链,并将请求沿着链传递,如果某个处理者能够处理请求则处理,否则将该请求交由上级处理。客户端只需将请求发送到职责链上,无须关注请求的处理细节,通过职责链将请求的发送者和处理者解耦了,这也是职责链的设计动机。        

           职责链模式可以简化对象间的相互连接,因为客户端和处理者都没有对方明确的信息,同时处理者也不知道职责链中的结构,处理者只需保存一个指向后续者的引用,而不需要保存所有候选者的引用。

            另外职责链模式增加了系统的灵活性,我们可以任意增加或更改处理者,甚至更改处理者的顺序,不过有可能会导致一个请求无论如何也得不到处理,因为它可能被放置在链末端。

    所以责任链模式有以下几个优点:

    • (1)降低耦合度,将请求的发送者和接收者解耦。反映在代码上就是不需要在类中写很多丑陋的 if….else 语句,如果用了职责链,相当于我们面对一个黑箱,只需将请求递交给其中一个处理者,然后让黑箱内部去负责传递就可以了。
    • (2)简化了对象,使得对象不需要链的结构。
    • (3)增加系统的灵活性,通过改变链内的成员或者调动他们的次序,允许动态地新增或者删除处理者
    • (4)增加新的请求处理类很方便。

    但是责任链模式也存在一些缺点:

    • (1)不能保证请求一定被成功处理
    • (2)系统性能将受到一定影响,并且可能会造成循环调用。
    • (3)可能不容易观察运行时的特征,而且在进行代码调试时不太方便,有碍于除错。

            责任链模式的UML结构图如下:

    责任链模式详情:Java设计模式之行为型:责任链模式

    16、行为型-观察者模式:

            观察者模式又称为 发布-订阅模式,定义了对象之间一对多依赖关系,当目标对象(被观察者)的状态发生改变时,它的所有依赖者(观察者)都会收到通知。一个观察目标可以对应多个观察者,而这些观察者之间没有相互联系,所以能够根据需要增加和删除观察者,使得系统更易于扩展,符合开闭原则;并且观察者模式让目标对象和观察者松耦合,虽然彼此不清楚对方的细节,但依然可以交互,目标对象只知道一个具体的观察者列表,但并不认识任何一个具体的观察者,它只知道他们都有一个共同的接口。

            但观察者模式的缺点在于如果存在很多个被观察者的话,那么将需要花费一定时间通知所有的观察者,如果观察者与被观察者之间存在循环依赖的话,那么可能导致系统崩溃,并且观察者模式没有相应的机制让观察者知道被观察对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。观察者模式的UML结构图如下:

     观察者模式详情:Java设计模式之行为型:观察者模式

    17、行为型-访问者模式:

            访问者模式就是一种分离对象数据结构与行为 (基于数据结构的操作) 的方法,通过这种分离,达到为一个被访问者动态添加新的操作而无需做其它修改的效果,使得添加作用于这些数据结构的新操作变得简单,并且不需要改变各数据结构,为不同类型的数据结构提供多种访问操作方式,这样是访问者模式的设计动机。

            除了使新增访问操作变得更加简单,也能够在不修改现有类的层次结构下,定义该类层次结构的操作,并将有关元素对象的访问行为集中到一个访问者对象中,而不是分散搞一个个的元素类中。

           但访问者模式的缺点在于让增加新的元素类变得困难,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,违背了“开闭原则”的要求;

            所以访问者模式适用于对象结构中很少改变,但经常需要在此对象结构上定义新的操作的系统,使得算法操作的增加变得简单;或者需要对一个对象结构中进行很多不同并且不相关的操作,并且需要避免让这些操作污染这些对象,也不希望在增加新操作时修改这些类的场景。

            访问者模式的UML结构图如下:

            从上面的 UML 结构图中我们可以看出,访问者模式主要分为两个层次结构,一个是访问者层次结构,提供了抽象访问者和具体访问者,主要用于声明一些操作;一个是元素层次结构,提供了抽象元素和具体元素,主要用于声明 accept 操作;而对象结构 ObjectStructure 作为两者的桥梁,存储了不同类型的对象,以便不同的访问者来访问,相同访问者可以以不同的方式访问不同的元素,所以在访问者模式中增加新的访问者无需修改现有代码,可扩展行强。

            在访问者模式使用了双分派技术,所谓双分派技术就是在选择方法的时候,不仅仅要根据消息接收者的运行时区别,还要根据参数的运行时区别。在访问者模式中,客户端将具体状态当做参数传递给具体访问者,这里完成第一次分派,然后具体访问者作为参数的“具体状态”中的方法,同时也将自己this作为参数传递进去,这里就完成了第二次分派。双分派意味着得到的执行操作决定于请求的种类和接受者的类型。

     访问者模式详情:Java设计模式之行为型:访问者模式

    18、行为型-中介者模式:

             中介者模式通过中介者对象来封装一系列的对象交互,将对象间复杂的关系网状结构变成结构简单的以中介者为核心的星形结构,对象间一对多的关联转变为一对一的关联,简化对象间的关系,便于理解;各个对象之间的关系被解耦,每个对象不再和它关联的对象直接发生相互作用,而是通过中介者对象来与关联的对象进行通讯,使得对象可以相对独立地使用,提高了对象的可复用和系统的可扩展性。

            在中介者模式中,中介者类处于核心地位,它封装了系统中所有对象类之间的关系,除了简化对象间的关系,还可以对对象间的交互进行进一步的控制。中介者模式的UML结构图如下:

            但是,中介者对象封装了对象之间的关联关系,导致中介者对象变得比较庞大复杂,所承担的责任也比较多,维护起来也比较困难,它需要知道每个对象和他们之间的交互细节,如果它出问题,将会导致整个系统都会出问题。

    中介者模式详情:Java设计模式之行为型:中介者模式

    19、行为型-命令模式:

            命令模式的本质是将请求封装成对象,将发出命令与执行命令的责任分开,命令的发送者和接收者完全解耦,发送者只需知道如何发送命令,不需要关心命令是如何实现的,甚至是否执行成功都不需要理会。命令模式的关键在于引入了抽象命令接口,发送者针对抽象命令接口编程,只有实现了抽象命令接口的具体命令才能与接收者相关联。

            使用命令模式的优势在于降低了系统的耦合度,而且新命令可以很方便添加到系统中,也容易设计一个组合命令。但缺点在于会导致某些系统有过多的具体命令类,因为针对每一个命令都需要设计一个具体命令类。

            命令模式的UML结构图如下:

    命令模式详情: Java设计模式之行为型:命令模式

    20、行为型-状态模式:

            状态模式,就是允许对象在内部状态发生改变时改变它的行为,对象看起来就好像修改了它的类,也就是说以状态为原子来改变它的行为,而不是通过行为来改变状态。

            当对象的行为取决于它的属性时,我们称这些属性为状态,那该对象就称为状态对象。对于状态对象而言,它的行为依赖于它的状态,比如要预订房间,只有当该房间空闲时才能预订,想入住该房间也只有当你预订了该房间或者该房间为空闲时。对于这样的一个对象,当它的外部事件产生互动的时候,其内部状态就会发生变化,从而使得他的行为也随之发生变化。

            状态模式的UML结构图如下:

     从上面的UML结构图我们可以看出状态模式的优点在于:

    (1)封装了转换规则,允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块

    (2)将所有与状态有关的行为放到一个类中,可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 

    但是状态模式的缺点在于:

    (1)需要在枚举状态之前需要确定状态种类

    (2)会导致增加系统类和对象的个数。

    (3)对 “开闭原则” 的支持并不友好,新增状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

    所以状态模式适用于:代码中包含大量与对象状态有关的条件语句,以及对象的行为依赖于它的状态,并且可以根据它的状态改变而改变它的相关行为。

    状态模式详情:Java设计模式之行为型:状态模式

    21、行为型-备忘录模式:

            备忘录模式提供了一种恢复状态的机制,在不破坏封装的前提下,捕获对象的某个时刻内部状态,并保存在该对象之外,保证该对象能够恢复到某个历史状态;备忘录模式将保存的细节封装在备忘录中,除了创建它的创建者之外其他对象都不能访问它,并且实现了即使要改变保存的细节也不影响客户端。但是备忘录模式都是多状态和多备份的,会早用较多的内存,消耗资源。备忘录模式的额UML结构图如下:

             备忘录模式的核心就是备忘录 Memento,在备忘录中存储的就是原发器 Originator 的部分或者所有的状态信息,而这些状态信息是不能够被其他对象所访问的,也就是说我们是不能使用备忘录之外的对象来存储这些状态信息,如果暴漏了内部状态信息就违反了封装的原则,故备忘录除了原发器外其他对象都不可以访问。所以为了实现备忘录模式的封装,我们需要对备忘录的访问做些控制:

    (1)对原发器:可以访问备忘录里的所有信息。

    (2)对负责人 caretaker:不可以访问备忘录里面的数据,但是他可以保存备忘录并且可以将备忘录传递给其他对象。

    (3)其他对象:不可访问也不可以保存,它只负责接收从负责人那里传递过来的备忘录同时恢复原发器的状态。

    备忘录模式详情:Java设计模式之行为型:备忘录模式

    22、行为型-迭代器模式:

            迭代器模式提供一种访问集合中的各个元素,而不暴露其内部表示的方法。将在元素之间游走的职责交给迭代器,而不是集合对象,从而简化集合容器的实现,让集合容器专注于在它所应该专注的事情上,更加符合单一职责原则,避免在集合容器的抽象接口层中充斥着各种不同的遍历操作。迭代器模式的UML结构图如下:

    迭代器模式详情:Java设计模式之行为型:迭代器模式

    23、行为型-解释器模式:

            解释器模式,就是定义语言的文法,并建立一个解释器来解释该语言中的句子,通过构建解释器,解决某一频繁发生的特定类型问题实例。

            解释器模式描述了如何构成一个简单的语言解释器,主要应用在使用面向对象语言开发的编译器中,它描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。    

            解释器模式中除了能够使用文法规则来定义一个语言,还能通过使用抽象语法树来更加直观表示、更好地地表示一个语言的构成,每一颗抽象语法树对应一个语言实例。抽象语法树描述了如何构成一个复杂的句子,通过对抽象语法树的分析,可以识别出语言中的终结符和非终结符类。 在解释器模式中由于每一种终结符表达式、非终结符表达式都会有一个具体的实例与之相对应,所以系统的扩展性比较好。

            解释器模式的UML如下:

     解释器模式详情:Java设计模式之行为型:解释器模式


    相关推荐阅读:

    Spring常见面试题总结

    SpringMVC常见面试题总结

    Mybatis常见面试题总结

    MySQL常见面试题总结

    Redis常见面试题总结

    RabbitMQ消息队列常见面试题总结

    ElasticSearch搜索引擎常见面试题总结

    计算机网络常见面试题总结

    操作系统常见面试题总结

    Java基础、集合、多线程常见面试题总结

    Java虚拟机常见面试题总结

    Java常见设计模式总结

    海量数据处理的方法总结


    参考文章:

    Java之美[从菜鸟到高手演变]之设计模式

    Java之美[从菜鸟到高手演变]之设计模式二

    Java之美[从菜鸟到高手演变]之设计模式三

    Java之美[从菜鸟到高手演变]之设计模式四

    展开全文
  • Java EE设计模式解析与应用》一书分析每种模式的意图,并通过各种可供选择的示例代码演示其实现,从而帮助广大开发者改进代码质量并提升架构设计水平。, 本书首先呈现最常见的GoF模式,接着循序渐进地讲解新模式;...
  • 图解Java设计模式(一)

    万人学习 2019-02-27 21:06:35
    本课程针对上述问题,有针对性的进行了升级 (1) 授课方式采用 图解+框架源码分析的方式,让课程生动有趣好理解 (2) 系统全面的讲解了设计模式,包括 设计模式七大原则、UML类图-类的六大关系、23种设计模式及其分类,...
  • 主要介绍了Java经典设计模式之责任链模式,简单说明了责任链模式的概念、原理,并结合实例形式分析java实现责任链模式的具体用法与相关注意事项,需要的朋友可以参考下
  • java设计模式经典教程

    2018-03-22 11:08:22
    最经典设计模式学习资料,没有之一,浅显易懂的分析设计模式使用场景,剖析设计模式设计思想,清晰的UML图表以及经典的代码案例,看完后恍然大悟,即使是java初学者也很容易理解学习。
  • java23种设计模式 1、设计模式是人们在面对同类型软件工程设计问题所总结出的一些有用经验。模式不是代码,而是某类问题的通用设计解决方案 2、4人组Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides总结...

    java23种设计模式及其源代码演示实现

    博主在CSDN已有三年,之前一直在看贴,受益颇多,不可多得的一个良好的学习平台,这一次,博主给大家分享一份传说中的java设计模式,源代码与其实现全部都有,希望有助于大家提高开发能力
    全文代码全部手敲,不会存在侵权问题,纯原创
    欢迎转载,但请附明出处
    以下请欣赏全文:文字有点多,因为十分详细


    java23种设计模式

    1、设计模式是人们在面对同类型软件工程设计问题所总结出的一些有用经验。模式不是代码,而是某类问题的通用设计解决方案
    2、4人组Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides总结写了《设计模式》
    3、设计模式的优点和用途
    4、学习设计模式最好的方式:在你的设计和以往的工程里寻找何处可以使用它们
    5、设计模式的本质目的是使软件工程在维护性、扩展性、变化性、复杂度方面成O(N)
    6、OO是原则,设计模式是具体方法、工具

    -------------------------------- 特别说明,以下案例皆是主类,将代码down下食用效果更佳! --------------------------------

    类图图例:

    Person
        1--eat() 代表Person类下面有一个eat() 方法
        1--eat(a,b,c) 代表Person类下面有一个eat方法,带3个参数
        1__name  __代表属性,Person下面有name属性
       -1__name __属性私有化
        1--Student  Person类下面有Student内部类
            2__name Student类下有name属性
     -->1--Student  Person类有子类Student,不在同一个文件
            2--run()  子类Student有run方法
    

    策略模式01

    1.分析项目中变化与不变部分
    2.多用组合少用继承;用行为类组合,而不是行为的继承.更有弹性
    案例:鸭子,不同种类的鸭子具有不同的组合行为
    策略模式案例

    观察者模式02

    1.多对一的依赖关系,Subject
    2.观察者注册,移除,通知
    3.java内置观察者,Observable是类不是接口,不能多重继承,具体如下:
    案例:天气预报项目,不同的公告板显示不同的公告内容
    观察者模式案例
    java内置观察者案例
    传统模式案例
    传统模式存在问题:一个需求新建一个变量,扩展性差,见传统模式

    装饰者模式03

    装饰者模式:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性。
    对于源有的代码,不进行修改,维护方便

    咖啡馆订单项目:传统面向对象开发,超类扩展,新调料,新单品,各自两两组合,类爆炸
    new 单品() new Milk(order) …
    装饰者模式案例
    java内置装饰者案例

    单例模式04

    有些对象只需要一个:线程池,缓存,硬件设备等
    如果多个实例会有造成冲突,结果的不一致性等问题
    确保类只有一个实例,同时又有全局访问点

    构造器私有化
    多线程问题及优化
    案例:巧克力工厂
    单例模式案例

    工厂模式05

    pizza项目:有准备,烘焙,切割,打包4个步骤,要方便pizza品种的扩展,便于维护,运行同时也能扩展
    传统模式:运行时,增加pizza品种,需要修改类,不满足运行同时扩展要求
    传统模式案例

    简单工厂模式:对象的实例化部分提取出来放入工厂类,满足了运行同时扩展要求
    但仍然有些问题:店铺扩展,A地一个工厂 B地一个工厂…100个地方需要100个工厂,每个工厂的pizza种类文化均不同

    public class SimplePizzaFactory {
        public Pizza CreatePizza(String ordertype) {
            Pizza pizza = null;
            if (ordertype.equals("cheese")) {
                pizza = new CheesePizza(); //多地工厂,B地pizza为CCPizza,则100个工厂需要100个不同的类
            } else if (ordertype.equals("greek")) {
                pizza = new GreekPizza();
            } else if (ordertype.equals("pepper")) {
                pizza = new PepperPizza();
            }
            return pizza;
        }
    }
    
    

    简单工厂模式案例

    工厂方法模式设计方案:将pizza项目里的pizza对象实例化功能抽象成抽象方法,在不同加盟店具体实现功能

    工厂方法模式案例

    抽象工厂模式:定义了一个接口用于创建相关或有依赖关系的对象族,而无需明确指定具体类
    工厂抽象成接口,指定工厂接入,子工厂与工厂无需在类里面直接修改代码增加变量,代码复用极高
    依赖抽象原则:
    1.变量不要持有具体类的引用
    2.不要让类继承自具体类,要继承自抽象类或接口
    3.不要覆盖基类中已实现的方法
    抽象工厂模式案例

    命令模式06

    家电自动化遥控器API项目:背景:一个遥控器两排按钮,如图示:
    ● ○
    ● ○
    ● ○
    ● ○
    ● ○
    左边●这一竖排自上而下分别控制灯,音响,增加音量…
    右边○这一竖排自上而下分别控制关灯,关闭音响,减小音量…
    要求自动化遥控器:扩展性好(当有新设备进来:扫地机器人,也接入该遥控器,要求极少量修改遥控器代码),维护性好

    传统模式方案问题:当新设备进来,代码耦合度极高,维护困难
    传统模式案例
    传统模式存在的问题

    命令模式:将请求,命令,动作等封装成对象,这样可以让项目使用这些对象来参数化其他对象.使得命令的请求者和执行者解耦
    命令模式案例
    宏命令,即一键功能

    适配器模式07

    插头与插座,汽车点烟器转usb充电器

    火鸡冒充鸭子项目
    背景:火鸡类,叫声AAA飞行:BBB 鸭子类叫声YYY,飞行FFF.调用适配器,使得某只火鸡调用适配器接口之后发出YYY叫声和FFF飞行

    适配器模式:将一个类的接口转换成另一种接口,让原本接口不兼容的类可以兼容
    从用户的角度看不到被适配者,是解耦的
    用户调用适配器转化出来的目标接口方法
    适配器调用被适配者的相关接口方法

    类适配器:通过多重继承目标接口和被适配者类方式实现适配
    目标

    适配器

    被适配者
    多重继承,其中继承的目标接口部分达到适配目的,而继承被适配者类的部分达到通过调用被适配者类里的方法实现目标接口的功能

    对象适配器和类适配器使用了不同的方法实现适配,对象适配器使用组合,类适配器使用继承

    适配器模式案例

    低版本java枚举器与高版本java迭代器适配案例

    外观模式08

    家庭影院项目:
    如下案例,现在要看电影:步骤为,打开爆米花机->打开投影仪->放下屏幕->放好CD->拿爆米花->关闭爆米花机…
    对象与对象之间没有关联,但必须同步方可进行事务
    如果每一个设备都有各自的按钮,操作过程将极其繁琐
    为此,引出外观模式:提供一个统一的接口,来访问子系统中一群功能相关接口
    其定义了一个高层接口,让子系统更容易使用

    与命令模式的区别:侧重点不一样:命令模式,将命令封装成对象,外观模式,将子系统功能暴露成为一个接口

    外观模式案例

    最少知识原则:尽量减少对象之间的交互,只留几个关系密切的对象,项目设计中不要让太多的类耦合在一起
    如何遵循:1.对象方法调用范围,调用自己,作为参数传进来的对象,此方法创建合实例化的对象,对象的组件但方法返回值例外
    最少知识原则Demo

    模板模式09

    咖啡和泡茶算法:
    模板模式:封装了一个算法步骤,并允许子类为一个或多个步骤方法提供实现
    模板模式可以使子类在不改变算法结构的情况下,重新定义算法中的某些步骤
    钩子函数:超类里面定义,子类重写,若不重写,则调用钩子函数,若重写,调用子类重写的函数,实现各自功能
    抽取完全相同的功能到超类案例
    部分子类实现不同的功能案例
    通用模板模式案例

    好莱坞原则:别调用我们,我们会调用你. 高层无需知道调用底层细节,解耦
    扩展性能和维护性能提高

    与策略模式的差异:模板封装步骤,策略模式针对行为等功能进行组合,如鸭子会飞,会叫,会用一个接口对其进行组合.而模板模式:会叫之后再会飞,抽象方法,子类进行实现

    迭代器模式10

    餐厅菜单合并项目:有两个餐厅,蛋糕餐厅使用ArrayList维护菜单,中餐厅使用数组维护菜单,现两个餐厅需要合并为一个餐厅,菜单如何维护?

    传统方案:每个餐厅自己的菜单,暴露出来给外部使用
    存在问题:
    1.扩展性能差,未来业务扩大,新增一个餐厅合并,该餐厅使用Hash表维护菜单,则必须新增类,暴露该hash菜单
    2.耦合度增加:案例中女招待类打印菜单方法使用了暴露的菜单,所以该方法必须修改

    详:
    传统模式案例

    迭代器模式:提供一种方法顺序访问一个聚合对象中的各个对象
    1.使用迭代器模式,餐厅的增加不影响Waitress类的修改,解耦
    2.餐厅未来修改菜单个数,仅需三方服务商修改其内部源码,直接调用迭代器接口即可,维护性强
    迭代器模式案例

    java内置迭代器:数组没有迭代器,自行实现.ArrayList有自己的迭代器,直接使用
    现有一使用hash表管理菜单的咖啡馆合并入两家餐馆,使用java内置迭代器实现以上项目,详:
    java内置迭代器

    单一责任原则:一个类应该只有一个引起变化的原因

    组合模式11

    餐馆增加新需求:给菜单某一项添加子菜单
    组合模式:将对象聚合成树形结构来表现"整体/部分"的层次结构
    组合模式能让客户以一致的方式来处理个别对象(菜单项)以及对象组合(子菜单),忽略对象组合与>个体对象之间的差别

    类结构如下:(最右边是超类)
    Waitress                              <Abstract>
      1--CakeHouseMenu                   MenuComponent
      1--DinerMenu                      ---------------
        2--Item                           operation()
        2--Item                           print()
        2--SubMenu                        remove()
          3--Item
          3--Item
          3--Item
      1--CafeMenu
        2--Item
        2--Item
        2--Item
    

    总结:餐厅合并之后,菜单含子菜单,总体菜单项如何进行遍历??
    1.数据结构不一样如何放一起?
    2.树形节点结构进行统一遍历
    3.菜单,子菜单,菜单项目全部继承一个超类,即组合模式,整体和局部区别通过超类抹去,解耦,屏蔽内部实现
    4.遍历:使用组合迭代器,巧妙利用堆栈遍历,获取菜单的同时又获取其迭代器,深层遍历
    具体案例如下:

    组合模式案例

    状态模式12

    项目:智能糖果机,用Java软件控制糖果机:待机,投入一元硬币,转动把手,滑落一颗糖果,
    待机(根据机器内糖果库存情况,是否提示售罄)
    糖果机根据状态的不同,行为结果就不同(如,没有塞入硬币转动把手不掉糖果一种结果和塞入硬币转动把手掉出糖果一种结果)

    传统设计方案:一个状态对应一个动作,采用switch case 强行进行功能实现
    则,如果公司增加新需求,加入游戏元素:有10%的概率可以拿到2粒糖果
    1.增加一个新状态赢家状态,每一个动作的所有switch均要修改,修改开放,耦合大,维护难
    2.基于接口开发,不应基于功能开发
    传统模式案例

    对于新需求,引入状态模式,如下:

    糖果机项目,状态和动作之间的关系可以形成如下表格

                                    insertCoin      returnCoin      turnCrank       dispense
    OnReadyState
    
    HasCoin
    
    SoldState
    
    SoldOutState
    
    WinnerState(新增需求,赢家状态)
    

    面向接口进行开发,所有状态抽象成一个状态接口
    类结构如下

    interface State                                     <interface>
        1--WinnerState                                     State
        1--OnReadyState                                 insertCoin()
        1--HasCoin                                      returnCoin()
        1--SoldOutState                                 trunCrank()
        1--SoldState                                    dispense()
    

    状态模式:根据内部状态的变化,改变对象的行为,看起来似乎修改了类

    状态模式案例
    策略模式一般情况下可以作为状态模式的基础,模板模式:部分拼接形成一个整体,状态模式:每一个状态都是整体

    代理模式13

    糖果机监控项目:你是公司上市老板:需要知道各个地方的糖果机运行情况,监控运行
    首先,本地糖果机监控,只需要设计一个监控类,类里面放糖果机集合,实现监控情况即可,具体案例如下:
    本地监控糖果机案例

    好,现公司壮大,糖果卖得火爆,为进行市场分析,需要进行远程监控糖果机,如何实现?
    由此引入代理监控方案–远程代理:远程对象(如其他地方糖果机)的本地代表(该糖果机的代表对象),通过它可以让远程对象当本地对象来调用
    远程代理通过网络和真正的远程对象沟通信息:

    Monitor <-> Agent ------------>Machine    Monitor访问Agent,Agent网络访问Machine,将结果返回给Monitor,相当于Monitor通过Agent代理,访问了Machine
    Java RMI实现远程代理:
        Monitor <-> RMI STUB ------------> RMI SKELET <-> Machine
    

    代理模式原理:为一个对象提供一个替身,控制对这个对象的访问

    Java RMI:计算机之间通过网络实现对象调用的一种通讯机制
    该机制可以让一台计算机上的对象可以调用另外一台计算机上的对象来获取远程数据

    Java RMI 案例如下:

    RMIHelloWord服务端
    RMIHelloWord客户端

    糖果机项目RMI服务端
    糖果机项目RMI客户端

    #####几种常见代理模式
    虚拟代理:虚拟代理为创建开销大的对象提供代理服务,真正的对象在创建前和创建中时,由虚拟代理扮演替身,如:浏览网页在线图片加载
    动态代理:运行时动态的创建代理类对象,并将方法调用转发到指定类
    保护代理:看一个找对象项目,个人信息,兴趣爱好,打分,只可以访问部分等

    使用 Proxy 类进行代理模式之保护代理设计:链接如下
    权限设置保护代理案例

    与装饰者模式的区别:装饰者模式,装饰之后会添加新功能;而代理模式是对目标对象访问的控制和管理

    复合模式14

    复合模式能解决一般性或一系列问题

    复杂鸭子项目:
    多种鸭子,不同鸭子叫声,飞行,游泳方式不同–策略模式
    鹅,需要加入几只普通的鹅–适配器模式(用鸭子模拟鹅)
    要统计鸭子叫声的次数–装饰者模式(动态的过程中增加新功能)
    统一产生鸭子–工厂模式
    管理一群鸭子–组合模式(迭代器)
    追踪某个鸭子的行为–观察者模式(注册,反注册,通知)

    MVC:模式与模式进行组合
    MVC:Model,View,Controller
    MVC解决什么类型的项目需求?
    为什么采用MVC结构?
    –结构复杂度降低,耦合度降低,不同部分独立升级

    Model:程序主体,代表业务数据和业务逻辑
    View:是与用户交互的界面,显示数据,接收输入但不参与实际业务逻辑
    Controller:接收用户输入,并解析反馈给Model

    MVC里的模式:
    Model与View和Controller是观察者模式
    View以组合模式管理控件(各种歌曲列表,弹窗等)
    View与Controller是策略模式关系,Controller提供策略

    以上很拗口,很难理解,以下作具体分析:

    分析一个播放器软件
    Model   播放器内部业务
      __Songs //属性,歌曲信息列表
      __State //属性,状态(按钮状态,播放状态,歌曲状态等)
      --start() //播放
      --pause() //暂停
      --stop() //停止
      --next() //下一首
      --previous() //上一首
      --getInfo() //获取歌曲信息
      
      
    View
     用户界面
     
        显示屏   
        按钮1,按钮2,按钮3,按钮4
        
        你好:这是一个Mp4图片,请自行想象
        
    Controller 策略,行为集,给按钮增加功能
      --Button1() 
      --Button2()
      --Button3()
      --Button4()
      
    模拟:用户按下了按钮3,想要切换下一首歌
        1.通过Controller解析出来该按钮的功能为切换下一首歌曲
        2.调用业务逻辑,Model.next()方法被调用,采用观察者模式通知View,信息变了,View采取相应措施
        3.歌曲播放完毕,Model观察者通知View歌曲结束,View相应进行响应,比如弹出一个窗口,歌曲播放完毕或者自动播放下一首歌等
        4.3这个也可以让Model通知Controller,具体业务具体分析
    
    

    Android App就是一个很典型的例子–>
    生命周期–模板模式
    整体上是MVC
    电池电量,观察者
    列表,模板

    桥接模式15

    桥接目的,分离抽象与实现,使抽象和实现可以独立变化
    系统多维度角度分类,而每一种分类又有可能变化,考虑使用桥接模式

    遥控器项目:索尼公司遥控器,厂家提供接口,遥控器调用接口实现遥控各种家电
    极简设计方案:类图如下:

    <interface Control>
        --On()
        --Off()
        --setChannel() //设置频道
        --setVolume() //设置音量
    
    SonyControl implements Control 实现各自方法
        --On()
        --Off()
        --setChannel()
        --setVolume()
    LGControl implements Control  实现各自方法
        --On()
        --Off()
        --setChannel()
        --setVolume()
    
    现有一TvControl想对Sony和LG进行控制,则有SonyTvControl和LGTvControl两个类
    

    极简设计方案

    该方案存在问题:新需求带来的设计问题,电视机厂家,新功能的遥控器出来,则新遥控器重新继承每一个类,类爆炸

    桥接模式:将实现与抽象放在两个不同的类层次重,使两个层次可以独立改变
    类图如下:

    <abstract>
    TvControlabs
      1__Control mControl __代表属性
      1--Onoff()          -- 代表方法
      1--nextChannel()
      1--preChannel()
    
     -->2\\TvControl \\代表类 -->代表子类,不属于同一个文件
          3--Onoff()
          3--nextChannel()
          3--preChannel()
     -->2\\newTvControl  
          3--Onoff()
          3--nextChannel()
          3--preChannel()
          3--setChannel()
          3--Back()
        
        
    mControl∈ 属于
        <interface>    
        Control
          1--On()
          1--Off()
          1--setChannel()
          1--setVolume()
            
       -->1\\SonyControl -->代表子类,但不属于同一个文件
            2--On()
            2--Off()
            2--setChannel()
            2--setVolume()
       -->1\\LGControl
       -->1\\SharpControl
        
    
    

    桥接模式案例

    生成器模式16

    生成器模式:

    将复杂对象创建过程封装
    隐藏类的内部结构
    允许对象通过几个步骤创建,并且可以改变工程(工厂模式只有一个步骤)

    度假计划项目:有3天度假计划,4天度假计划(每个计划都是不同对象),如何生成?使用生成器模式:
    生成器模式:封装一个复杂对象构造过程,并允许按步骤构造
    具体案例:生成器模式案例

    省略抽象生成器类
    省略指导者类

    与抽象工厂的差异:主要用于创建复杂,大的对象

    责任链模式17

    购买请求决策项目:决策因素:价格
    决策级别:组长,部长,副总,总裁
    考虑扩展性
    如果多个对象都有机会处理请求,责任链可使请求的发送者和接受者解耦,请求沿着责任链传递,直到有一个对象处理了它为止.
    该模式简化了对象,因为无须知道链结构
    该模式可以动态增加或删减处理请求的链结构
    该模式请求从链开头进行遍历,对性能有一定损耗
    该模式并不一定保证请求被处理

    项目类图如下:

    PurchaseRequest->A类(请求没处理,抛!)->B类(请求没处理,抛!)->C类(请求没处理,抛!)->D类(请求被处理)
    

    责任链模式案例
    适用于:有多个对象可以处理一个请求,不明确接收者情况

    与状态模式的差异:责任链,注重请求的传递,状态模式,注重对象状态的转换

    蝇量模式18

    景观设计软件项目:
    树:XY坐标,树的大小,外观,需要很多树;1000W棵树,需要对象Tree 1000W 个,小对象大量级的问题解决

    传统方案设计:传统模式

    分析:

    Tree
        1__xCoord
        1__yCoord
        1__age
        1--display()
    1000W个Tree对象实在太多,影响性能,该如何做?
    
    引入蝇量模式
    
    TreeManager
        1__xArray
        1__yArray
        1__AgeArray
        1--displayTrees()
    
    Tree
        1--display()
    

    蝇量模式案例1

    蝇量模式:通过共享的方式高效地支持大量细粒度的对象,适用于大量细粒度对象(上千万),且这些对象的外部状态不多
    优缺点分析:
    优点:
    –减少运行时对象实例个数,节省创建开销和内存
    –许多虚拟对象状态集中管理
    缺点:
    –系统设计更加复杂
    –专门维护对象外部状态

    项目有新需求:增加一些草 类图如下:

    PlantFactory
        1--getPlant()  (PlantManager、Plant类通过该方法显示具体结果)
       
    PlantManager
        1__xArray
        1__yArray
        1__AgeArray
        1__typeArray
        1--displayTrees() -> Plant.display()
        
    <abstract> Plant
        1--display()
     -->1\\Grass
            2--display()
     -->1\\Tree
            2--display()
    

    如何才能实现内存最佳化利用??
    引入草对象按蝇量模式设计案例2

    解释器模式19

    大数据统计项目:按照计算模型对现有数据统计,分析,预测,计算模型需要运行期编辑,如何设计??写函数,写sql?
    最好能有一个通用方案,各部门都能通用,维护也方便,扩展也方便,引入解释器模式:
    解释器模式:计算模型按正常算式方式书写,解释器处理语法逻辑;定义一个语法,定义一个解释器,该解释器处理该语法句子

    计算模式里有两类符号:数据和计算符(±*/语法规则,优先级等)
    逆波兰算法分析算式语法
    用解释器模式处理数据

    优点:
    –容易修改,修改语法规则只要修改相应非终结符即可
    –扩展方便,扩展语法,增加非终结符类即可
    缺点:
    –复杂语法,类结构巨复杂,不便管理和维护,尽量不要在重要的模块中使用
    –采用递归方式,效率会受影响

    可以仅作了解:实际系统开发中使用的非常少
    使用场合:数据分析工具,报表设计工具,科学计算工具

    原理类图如下:将某些复杂问题,表达为某种语法规则,然后构建解释器解释处理这类句子

    用户Client发出一个算式Context,定义解释器:
    AbstractExpression
        1--Interpret(Context)
     -->1\\TerminalExpression  子类
            2--Interpret(Context)
     -->1\\NoterminalExpression  子类
            2--Interpret(Context) 
    

    回到大数据统计项目,该项目采用解释器模式进行:类图如下

    <abstract>
    AbstractExpresstion
        1--Interpret()
     -->1--VarExpresstion 变量表达式子类
            2--Interpret()
     -->1--SymbolExpresstion 符号表达式子类
            2--Interpret()
         -->2--AddExpresstion +
                3--Interpret()
         -->2--SubExpresstion -
                3--Interpret()
         -->2--MutilExpresstion *
                3--Interpret()
         -->2--DivExpresstion /
                3--Interpret()
    

    解释器模式案例

    中介者模式20

    中介者模式,用一个中介对象来封装一系列的对象交互
    中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互

    优点:

    –彼此解耦对象,增加对象复用
    –控制逻辑集中,简化系统维护
    –对象之间传递消息变得简单而且大幅减少
    –提高系统灵活,易于扩展和维护

    缺点:

    –中介是中心,出现问题则会影响整个系统
    –中介者本身对象可能会变得过于复杂源于设计不当

    智慧房屋项目:公司专业生产各种房子,房子里有智慧闹钟,咖啡机,电视机,窗帘等,实现以下需求
    某一时刻,闹钟响起,咖啡机自动泡咖啡,同时自动打开电视机,等待咖啡机泡咖啡结束窗帘自动落下,房间灯自动亮起…
    传统设计逻辑:Alarm—1号,TV—2号,CoffeeMachine—3号,Curtains—4号
    1给2,3发消息,3给2,4发消息…
    对象之间耦合性过强,扩展复用性能差,维护难,不好调试

    中介者模式:引入一个中介,Mediator,对象之间省去互相沟通,各对象仅与中介沟通,由中介对结果进行反馈
    逻辑:1–中介,2–中介,3–中介,4–中介,中介–1,2,3,4

    中介者模式案例

    中介者模式与观察者模式:观察者模式广播,中介者定向

    适用场合:一组对象之间通信方式比较复杂,导致相互依赖,结构混乱;一个对象引用许多其他对象并直接与这些对象通信,导致难以复用该对象

    备忘录模式21

    备忘录模式:在不破坏封装的前提下,存储关键对象的重要状态,从而可以把对象还原到存储的那个状态
    游戏项目:游戏进度状态保存问题.对象状态,场景状态,大型项目,每个人开发自己的保存功能,这个效率将十分低
    引入备忘录模式:统一功能,每一个人开发的保存功能用一个类进行管理,设计MemetoIF接口,别人开发的细节自己将看不到,保证信息安全

    优点:

    –状态存储在外面,不和关键对象混一起,可以帮助维护内聚
    –提供容易实现的恢复能力
    –保持关键对象的数据封装

    缺点:

    –资源消耗上面备忘录对象会很昂贵
    –存储和还原比较耗时

    场合:必须保存一个对象在某一个时刻的整体或部分状态,在对象以外的地方进行恢复

    备忘录模式案例

    原型模式22

    电子账单项目:银行的电子账单,广告信,特点,量大,时间要求紧
    传统设计模式案例
    问题来了:500万用户发送邮件,一封邮件0.1s发出,需要50Ws…6天!

    那么解决方案:SendMail多线程并发进行,需要在每一封邮件发送前新创建对象,每次new,内存资源浪费
    引入原型模式:一个对象,通过内存复制创建新一模一样对象,该对象指向其他内存区域,无须知道相应类的信息
    优点:

    –使用原型模式创建对象比直接new一个对象更有效
    –隐藏制造新实例复杂性
    –重复创建相似对象时可以考虑使用

    缺点

    –深层复制比较复杂
    –每一个类必须配备一个克隆方法

    注意事项:

    1.使用原型模式复制对象不会调用类的构造方法!!!所以单例模式与原型模式是冲突的
    2.final 对象由于不能改动(其内存空间固定),故采用原型模式的类无法使用final声明的对象
    3.Object类的clone方法只会拷贝对象中的基本数据类型,对于数组,容器,引用对象等都不会拷贝,这就是浅拷贝
    4.实现深拷贝必须将原型模式中的数组,容器对象,引用对象等另外拷贝

    原型模式案例深拷贝
    适用场合:

    1.复制对象结构和数据
    2.希望对目标对象的修改不影响既有的原型对象
    3.创建对象成本较大的情况下

    访问者模式23

    雇员管理系统项目:Employee,需要添加一些新的操作功能,具体案例如下:
    传统模式案例 违背开闭原则

    访问者模式:对于一群对象,在不改变数据结构的前提下,增加作用于这些结构元素新的功能,适用于数据结构相对稳定,
    数据结构和作用于其上的操作解耦,使得操作集合可以相对自由地演化

    优点:

    1.一个访问者一个功能,符合单一职责原则
    2.扩展性良好
    3.有益于系统的管理和维护

    缺点:

    1.增加新的元素类变得很困难,修改算法
    2.破坏封装性

    访问者模式案例

    注意事项:

    1.系统有比较稳定的数据结构
    2.与迭代器的关系:迭代器提供访问者注入的一种方式,访问者对对象进行处理

    适用场合:数据结构比较稳定,需求又经常变化,那么访问者模式比较适合

    写在最后:

    模式:在某些场景下,针对某类问题的某种通用解决方案,其中,场景是项目环境,问题是约束条件,项目目标;解决方案:通用可以复用的设计,解决约束达到目标
    (实际经验的总结)
    设计模式的三个分类
        --创建型模式:对象实例化的模式,解耦了对象的实例化过程
        --结构型模式:把类或对象结合一起形成更大的结构
        --行为型模式:类和对象如何交互,及划分责任和算法
    

    简单工厂:一个工厂类根据传入的参量决定创建出哪一种产品类的实例
    工厂方法:定义一个创建对象的接口,让子类决定实例化哪一个类
    抽象工厂:创建相关或依赖对象的家族,而无需明确指定具体类
    单例模式:类只有一个实例,提供一个全局访问点
    生成器模式:封装一个复杂对象的构建过程,可以按步骤构造
    原型模式:通过复制现有的实例来创建新的实例
    适配器模式:将一个类的方法接口转换成客户希望的另外一个接口
    组合模式:将对象组合成树形结构以表示"部分-整体"的层次结构
    装饰模式:动态地给对象添加新的功能
    代理模式:为其他对象提供一个代理以控制对这个对象的访问
    蝇量模式:通过共享技术有效地支持大量细粒度的对象
    外观模式:提供统一的方法来访问子系统的一群接口
    桥接模式:将抽象部分与它的实现部分分离,使它们都可以独立地变化
    模板模式:定义一个算法结构,而将一些步骤延迟到子类中实现
    解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器
    策略模式:定义一系列的算法,把它们封装起来,并且使它们可相互替换
    状态模式:允许一个对象在其内部状态改变时改变它的行为
    观测者模式:对象间的一对多的依赖关系
    备忘录模式:在不破坏封装性的前提下,保存对象的内部状态
    中介者模式:用一个中介对象来封装一系列的对象交互
    命令模式:将命令请求封装为一个对象,使得可用不同的请求来进行参数化
    访问者模式:在不改变数据结构的前提下,增加作用于一组对象元素新的功能
    责任链:请求发送者和接收者之间解耦,使得多个对象都有机会处理这个请求
    迭代器:一种遍历访问聚合对象中各个元素的方法,不暴露该对象的内部结构

    对象设计的六大原则:
    组合复用原则:多用组合,少用继承,找到变化部分,抽象,封装变化(has A 与 is A).鸭子项目01

    依赖倒置原则:

    依赖:成员变量,方法参数,返回值,依赖于抽象,不要依赖于具体
    高层模块不应该依赖低层,且都应该依赖其抽象
    具体应该依赖抽象,抽象不应该依赖具体
    针对接口编程,不要针对实现编程
    项目架构:以抽象为基础搭建

    开闭原则:对扩展开放,对修改关闭,通过扩展已有软件系统,提供新功能,对修改的关闭,保证稳定性和延续性

    里氏替换原则:

    引用基类的地方必须能透明地使用其子类对象
    子类扩展父类功能,不能破坏父类原有的功能
    设计继承,子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
    子类重载父类方法,方法的形参要比父类方法的参数更宽松
    子类实现父类抽象方法,方法的返回值要比父类更严格

    迪米特法则:

    一个对象应该与其他对象保持最少了解尽量降低类与类之间的耦合

    接口隔离原则:一个类对另一个类的依赖应该建立在最小的接口上

    单一职责原则:实际工作中很难达到,即一个类只负责一项职责

    用模式来思考:
    保持简单:

    尽可能用最简单的方式解决问题

    设计模式非万能:

    模式是通用问题的经验总结
    考虑它对其他部分影响
    不需要预留任何弹性时,删除掉模式

    何时需要模式:

    设计中会变化的部分,通常就是需要考虑模式的地方
    重构时,带进模式

    重构的时间就是模式的时间:

    利用模式来重构

    展开全文
  • 主要介绍了Java设计模式常用原则解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • Java设计模式

    千次阅读 多人点赞 2019-09-03 23:20:31
    Java设计模式 1.工厂模式 工厂模式一般分为简单工厂、工厂、抽象工厂3钟情况,属于创建型设计模式。 2.生成器模式 3.观察者模式 4.桥接模式 5.代理模式 6.状态模式 7.访问者模式 ...

    Java设计模式

    1.工厂模式

    2.生成器模式

    3.观察者模式

    4.桥接模式

    5.代理模式

    6.状态模式

    7.访问者模式

    8.命令模式

    9.装饰器模式

    10.组合模式

    1.工厂模式

    工厂模式一般分为简单工厂、工厂、抽象工厂3种情况,属于创建型设计模式。

    简单工厂(静态工厂)

    //定义小汽车接口:ICar.java
    public interface ICar{
      //由于工厂模式仅关系对象的创建,为说明方便,无需定义方法
    }
    
    //下面定义高、中、低档具体的汽车
    //高档小汽车:TopCar.java
    public class TopCar implements ICar{
    }
    //中档小汽车:MidCar.java
    public class MidCar implements ICar {
    }
    //低档小汽车:LowCar.java
    public class LowCar implements ICar {
    }
    
    //简单工厂:CarSimpleFactory.java
    public class CarSimpleFactory {
        public static final String TOPTYPE = "toptype";
        public static final String MIDTYPE = "midtype";
        public static final String LOWTYPE = "lowtype";
        public static ICar create(String mark){
        ICar obj = null;
        if(mark.equals(TOPTYPE)){ //如果是高档类型
          obj = new TopCar();  //则创建高档车对象
        }
        else if(mark.equals(MIDTYPE)){
        obj = new MidCar();
      }
        else if(mark.equals(LOWTYPE)){
        obj = new LowCar();
      }
        return obj;    //返回选择的对象
      }
    }
    
    //测试程序:CarTest.java
    public class CarTest {
      public static void main(String[] args) {
      //从工厂中创建对象
        ICar obj = CarSimpleFactory.create("toptype");
      }
    }
    

    工厂

    //定义小汽车接口:ICar.java
    public interface ICar {
    //由于工厂模式仅关系对象的创建,为说明方便,无需定义方法
    }
    //定义高、中、低档具体的小汽车
    //高档小汽车:TopCar.java
    public class TopCar implements ICar {
    }
    //中档小汽车:MidCar.java
    public class MidCar implements ICar {
    }
    //低档小汽车:LowCar.java
    public class LowCar implements ICar {
    }
    //定义抽象工厂:AbstractFactory.java
    public abstract class AbstractFactory {
    public abstract ICar create();
    }
    //定义高档小汽车工厂:TopFactory.java
    public class TopFactory extends AbstractFactory {
    public ICar create() {
        return new TopCar(); //高档工厂生成高档小汽车对象
      }
    }
    //定义中档小汽车工厂:MidFactory.java
    public class MidFactory extends AbstractFactory {
    public ICar create() {
        return new MidCar(); //中档工厂生成中档小汽车对象
      }
    }
    //定义低档小汽车工厂:LowFactory.java
    public class LowFactory extends AbstractFactory {
    public ICar create() {
        return new LowCar(); //低档工厂生成低档小汽车对象
      }
    }
    //测试类:CarTest.java
    public class CarTest {
    public static void main(String []args){
        AbstractFactory obj = new TopFactory();//多态创建高档工厂
        ICar car = obj.create();    //获得高档工厂中的小汽车对象
      }
    }
    

    抽象工厂

    //小汽车接口
    public interface ICar { }
    public class TopCar implements ICar { }
    public class MidCar implements ICar { }
    public class LowCar implements ICar { }
    
    //定义公共汽车接口、高、中、低档公共汽车类
    public interface IBus { }
    public class UpBus implements IBus { }
    public class MidBus implements IBus { }
    public class DnBus implements IBus { }
    
    //定义抽象工厂:AbstractFactory.java
    public absttract class AbstractFactory {
    public abstract ICar createCar(); //产生小汽车对象
    public abstract IBus createBus(); //产生公共汽车对象
    }
    
    //定义高档工厂:TopFactory.java
    public class TopFactory extends AbstractFactory {
      public ICar createCar() {
        return new TopCar();  //高档工厂生成高档小汽车对象
      }
      public IBus createBus() {
        return new UpBus();  //高档工厂生成高档公共汽车对象
      }
    }
    
    //定义中档工厂:MidFactory.java
    public class MidFactory extends AbstractFactory {
      public ICar createCar() {
        return new MidCar();  //中档工厂生成中档小汽车对象
      }
      public IBus createBus() {
        return new MidBus();  //中档工厂生成中档公共汽车对象
      }
    }
    //定义低档工厂:LowFactory.java
    public class LowFactory extends AbstractFactory {
      public ICar createCar() {
        return new LowCar();  //低档工厂生成中档小汽车对象
      }
      public IBus createBus() {
        return new DnBus();  //低档工厂生成中档公共汽车对象
      }
    }
    

    2.生成器模式

    生成器模式也称为建造者模式。生成器模式的意图在于将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。在软件设计中,有时候面临着一个非常复杂的对象的创建工作。这个复杂的对象通常可以分成几个较小的部分,由各个子对象组合出这个复杂对象的过程相对来说比较稳定,但是子对象的创建过程各不相同并且可能面临变化。根据OOD中的OCP原则,应该对这些子对象的创建过程进行变化封装。

    生成器思路是产品类与创建产品的类相分离。产品类仅1个,创建产品的类有n个。

    生成器设计模式涉及4个关键角色:产品(Product)、抽象生成器(IBuild)、具体生成器(Builder)、指挥者(Director)。
    在这里插入图片描述

    (1)定义1个产品类。
    public class Unit1{……}
    public class Unit2{……}
    public class Unit3{……}
    public class Product {
    Unit1 u1;
    Unit2 u2;
    Unit3 u3;
    }
    由于不在该类完成Product类对象的创建,所以无需显示定义构造方法。
    
    (2)定义n个生成器Build类。
    根据语义,生成器是用来生成Product对象的,因此一般来说,Product是生成器类的一个成员变量;
    根据语义,每创建一个Product对象,本质上都需要先创建Unit1,Unit2,…, UnitN,再把它们组合成所需的Product对象,
    因此需要n个createUnit()方法及一个组合方法composite();由于createUnit()及composite()是共性,
    因此可定义共同的生成器类接口, n个生成器类均从此接口派生即可。代码如下。
    //定义生成器类接口IBuild
    public interface IBuild {
    public void createUnit1();
    public void createUnit2();
    public void createUnit3();
    public Product composite();    //返回值是Product对象
    }
    //定义3个生成器类
    public class BuildProduct implements IBuild { //生成第一种Product
    Product p = new Product();     //Product是成员变量
    public void createUnit1() {
    //p.u1= ...       //创建Unit1
    }
    public void createUnit2() {
    //p.u2 = ...       //创建Unit2
    }
    public void createUnit3() {
    //p.u3 =  //创建Unit3
    }
    public Product composite() {
    //...   //关联Unit,Unit2,Unit3
    return p;  //返回Product对象p
    }
    }
    public class BuildProduct2 implements IBuild {  //生成第2种Product
    Product p = new Product();//Product是成员变量
    public void createUnit() {/*p.u = ...... */} //创建Unit
    public void createUnit2(){/*p.u2 = ...... */} //创建Unit2
    public void createUnit3(){/*p.u3 = ...... */} //创建Unit3
    public Product composite() {
    //......    //关联Unit1,Unit2,Unit3
    return p;   //返回Product对象p
    }
    }
    public class BuildProduct3 implements IBuild {  //生成第3种Product
    Product p = new Product();//Product是成员变量
    public void createUnit1() {/*p.u1 = ...... */} //创建Unit1
    public void createUnit2(){/*p.u2 = ...... */} //创建Unit2
    public void createUnit3(){/*p.u3 = ...... */} //创建Unit3
    public Product composite() {
    //......  //关联Unit1,Unit2,Unit3
    return p;  //返回Product对象p
    }
    }
    通过上述代码可知,若需求分析发生变化,只需增加或删除相应的生成器类即可,无需修改已有的类代码。
    (3)定义1个统一调度类,也叫指挥者(Director)类,是对生成器接口IBuild的封装。该类及简单的测试代码如下。
    public class Director {
    private IBuild build;
    public Director(IBuild build){
    this.build = build;
    }
    public Product build(){
    build.createUnit1();
    build.createUnit2();
    build.createUnit3();
    return build.composite();
    }
    public static void main(String []args){
    IBuild build = new BuildProduct();
    Director direct = new Director(build);
    Product p = direct.build();
    }
    }
    

    3.观察者模式

    观察者设计模式适合解决多种对象跟踪一个对象数据变化的程序结构问题,有一个称作“主题”的对象和若干个称作“观察者”的对象。有一个主题数据——温度,3个观察者—温度日志、温度曲线、温度报警。因此观察者设计模式涉及两种角色:主题和观察者。
    观察者设计模式可以从以下递推中得出一些重要结论。
    ● 主题要知道有哪些观察者对其进行监测,因此主题类中一定有一个集合类成员变量,包含了观察者的对象集合。
    ● 既然包含了观察者的对象集合,那么,观察者一定是多态的,有共同的父类接口。
    ● 主题完成的主要功能是:可以添加观察者,可以撤销观察者,可以向观察者发消息,引起观察者响应。这三个功能是固定的,因此主题类可以从固定的接口派生。
    因此,编制观察者设计模式,要完成以下功能类的编制。
    ● 主题ISubject接口定义。
    ● 主题类编制。
    ● 观察者接口IObserver定义。
    ● 观察者类实现。
    在这里插入图片描述

    (1)观察者接口IObserver。
    
        public interface IObserver {
            public void refresh(String data);
        }
        
    (2)主题接口ISubject。
    
        public interface ISubject {
            public void register(IObserver obs);       //注册观察者
            public void unregister(IObserver obs);     //撤销观察者
            public void notifyObservers();             //通知所有观察者
        }
        
    (3)主题实现类Subject。
    
        public class Subject implements ISubject {
            private Vector<IObserver> vec = new Vector();  //观察者维护向量
            private String data;                           //主题中心数据
    
            public String getData() {
                return data;
            }
            public void setData(String data) {              //主题注册(添加)
                this.data = data;
            }
            public void register(IObserver obs) {           //主题注册(添加)观察者
             vec.add(obs);
            }
    
            public void unregister(IObserver obs) {         //主题撤销(删除)观察者
                if(vec.contains(obs))
                    vec.remove(obs);
            }
            public void notifyObservers(){             //主题通知所有观察者进行数据响应
                for(int i=0; i<vec.size(); i++){
                    IObserver obs = vec.get(i);
                    obs.refresh(data);
                }
            }
        }
        
        主题实现类Subject是观察者设计模式中最重要的一个类,包含了观察者对象的维护向量vec以及主题中心数据data变量与具体观察者对象的关联
        方法(通过nitofyObservers())。也就是说,从此类出发,可以更深刻地理解ISubject为什么定义了3个方法、IObserver接口为什么定义了1个方法。
        
    (4)一个具体观察者类Observer。
    
        public class Observer implements IObserver {
            public void refresh(String data) {
                System.out.println("I have received the data:" +data);
            }
        }
        
    (5)一个简单的测试类Test。
    
        public class Test {
            public static void main(String[] args) {
                IObserver obs = new Observer();    //定义观察者对象
                Subject subject = new Subject();
                //定义主题对象
                subject.register(obs);             //主题添加观察者
                subject.setData("hello");          //主题中心数据发生变动
                subject.notifyObservers();         //通知所有观察者进行数据响应
            }
        }
        
    该段代码的含义是:当主题中心数据变化(通过setData方法)后,主题类subject要调用notifyObservers()方法,
    通知所有观察者对象接收数据并进行数据响应。
    

    4.桥接模式

    桥接模式是关于怎样将抽象部分与它的实现部分分离,使它们都可以独立地变化的成熟模式。
    在这里插入图片描述

    (1)定义邮寄接口IPost。
    
        public interface IPost{   //邮局
            public void post();   //发送功能
        }
        
    (2)两个具体邮寄类SimplePost、MarkPost。
    
        //平信邮寄类SimplePost
        class SimplePost implements IPost{     //平信
            public void post(){                //发送
                System.out.println("This is Simple post");
            }
        }
        //挂号邮寄类
        class MarkPost implements IPost{       //挂号
            public void post(){                //发送
                System.out.println("This is Mark post");
            }
        }
        
      经过(1)、(2)的论述,完成了语义的前半部分定义:邮局有发送功能;发送有两种方式,平邮和挂号。
      
    (3)抽象事物类AbstractThing。
    
        abstract class AbstractThing{ //抽象事物
    
            private IPost obj;         //有抽象发送功能
            public AbstractThing(IPost obj){
                this.obj = obj;
            }
            public void post(){
                obj.post();
            }
        }
        
    该类是桥接模式的核心。分析语义“信件和包裹共享平邮与挂号功能”:信件、包裹是两个不同的事物,它们有共享的功能,
    也一定有相异的功能。共享的功能一定能封装到一个类中,又由于该类不能代表一个具体的事物,所以把它定义成abstract类是恰当的。
    该类共享的是多态成员obj,是IPost类型的,是抽象的、泛指的,用一条语句表明了事物共享平邮和发送功能。
    
    (4)具体事物类Letter、Parcel。
    
        //信件类Letter
        class Letter extends AbstractThing{
            public Letter(IPost obj){
                super(obj);
            }
            //其他独有变量和方法
        }
        //包裹类Parcel
        class Parcel extends AbstractThing{
            public Parcel(IPost obj){
                super(obj);
            }
            //其他独有变量和方法
        }
        
        //编制一个简单的测试类
        public class Test {
            public static void main(String[] args) {
                IPost p = new SimplePost();
    
                Letter letter = new Letter(p);
                letter.post();
            }
        }
        
    第一种情况:若增加了新的事物,则只需从Abstract派生一个类即可,其他无需改变。
    
        class NewThing extends AbstractThing{
            public NewThing(IPost obj){
                super(obj);
            }
            //其他独有变量和方法
        }
        
    第二种情况:若增加了新的邮寄类别,比如特快专递,则只需从IPost接口派生一个类即可,其他无需改变。
    
        class EMSPost implements IPost{        //特快专递
        public void post(){                //发送
                System.out.println("This is EMS post");
            }
        }
    

    5.代理模式

    代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。代理模式则是一种可以很好实现客户对象与代理对象分离的策略。

    代理模式的定义如下:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式的英文叫作Proxy或Surrogate,它是一种对象结构型模式。其抽象UML图如图所示
    在这里插入图片描述
    代理模式包含如下角色
    ● ISubject:抽象主题角色,是一个接口。该接口是对象和它的代理共用的接口。
    ● RealSubject:真实主题角色,是实现抽象主题接口的类。
    ● Proxy:代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。以买电视为例,其代码如下。
    (1)定义抽象主题——买电视。

    interface ITV{
            public void buyTV();
        }
    

    (2)定义实际主题——买电视过程。

    class Buyer implements ITV{
        public void buyTV(){
            System.out.println("I have bought the TV by buyer proxy");
        }
    }
    

    真正的付费是由购买者完成的。
    (3)定义代理。

    class BuyerProxy implements ITV{
        private Buyer buyer;
        public BuyerProxy(Buyer buyer){
            this.buyer = buyer;
        }
        public void buyTV(){
            preProcess();
            buyer.buyTV();
            postProcess();
        }
        public void preProcess(){
            //询问客户需要电视类型、价位等信息
        }
        public void postProcess(){
            //负责把电视送到客户家
        }
    }
    

    电视代理商BuyerProxy与购买者Buyer都实现了相同的接口ITV,是对Buyer对象的进一步封装。着重理解buyTV()方法:首先代理商要通过preProcess()询问客户买电视的类型、价位等信息,然后购买者通过buyer.buyTV()自己付费完成电视购买,最后代理商通过postProcess()协商具体的送货服务、产品三包等。

    代理模式最突出的特点是:代理角色与实际主题角色有相同的父类接口。常用的代理方式有4类:虚拟代理、远程代理、计数代理、动态代理

    虚拟代理
    虚拟代理的关键思想是:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。当用户请求一个“大”对象时,虚拟代理在该对象真正被创建出来之前扮演着替身的角色;当该对象被创建出来之后,虚拟代理就将用户的请求直接委托给该对象。

    远程代理
    远程代理的含义是:为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以在同一台主机中,也可在另一台主机中。也就是说,远程对象驻留于服务器上,客户机请求调用远程对象调用相应方法,执行完毕后,结果由服务器返回给客户端。
    在这里插入图片描述
    计数代理
    当客户程序需要在调用服务提供者对象的方法之前或之后执行日志或计数的额外功能时,就可以使用计数代理模式。计数代理模式并不是把这些额外操作的代码直接添加到源服务中,而是把它们封装成一个单独的对象,这就是计数代理。

    动态代理
    对代理模式而言,一个主题类与一个代理类一一对应,这也是静态代理模式的特点。
    静态代理模式简图
    但是,也常存在这样的情况,有n个主题类,但是代理类中的“前处理、后处理”都是一样的,仅调用主题不同,需要编制如图所示的程序框架。
    [动态代理模式简图]
    也就是说,多个主题类对应一个代理类,共享“前处理、后处理”功能,动态调用所需主题,大大减小了程序规模,这就是动态代理模式的特点。实现动态代理的关键技术是反射。

    6.状态模式

    状态模式为研究各种状态以及状态间相互转化的实现方式提出了一种较好的设计思路。

    ● 状态类有共同的父接口(或抽象类), n个不同的状态实现类。
    ● 事物类中包含状态类父接口成员变量声明,用以反映语义“事物有n个状态”。
    ● 事物类中一定有方法选择分支,判断事物当前处于何种状态。

    状态模式必须完成如下内容的编制:
    ● State:状态接口,封装特定状态所对应的行为。
    ● ConcreteState:具体实现状态处理的类。
    ● Context:事物类,也称上下文类,通常用来定义多态状态接口,同时维护一个用来具体处理当前状态的示例对象。

    状态模式的UML抽象类图如图所示
    在这里插入图片描述
    状态模式的具体抽象代码如下。
    (1)定义状态抽象接口IState。

    interface IState{
        public void goState();
    }
    

    (2)定义状态实现类。

    class ConcreteStateA implements IState{//定义状态A类
        public void goState(){
            System.out.println("This is ConcreteStateA");
        }
    }
    class ConcreteStateB implements IState{//定义状态B类
        public void goState(){
            System.out.println("This is ConcreteStateB");
        }
    }
    

    (3)定义状态上下文维护类Context。

    class Context{            //上下文有n种状态
        private IState state;
        public void setState(IState state){
            this.state = state;
        }
        public void manage(){
            //此处代码根据条件选择某种状态
            state.goState(); //执行某种状态功能
        }
    }
    

    Context类是实现状态模式的关键,本部分仅列出了状态模式的基本代码

    7.访问者模式

    访问者模式的目的是封装一些施加于某种数据结构元素之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。为不同类型的元素提供多种访问操作方式,且可以在不修改原有系统的情况下增加新的操作方式,这就是访问者模式的模式动机。

    访问者模式抽象类图
    在这里插入图片描述
    访问者模式主要涉及以下四种角色:
    ● IElement:抽象的事物元素功能接口,定义了固定功能方法及可变功能方法接口。
    ● Element:具体功能的实现类。
    ● IVisitor:访问者接口,为所有访问者对象声明一个visit方法,用来代表为对象结构添加的功能,原则上可以代表任意的功能。
    ● Visitor:具体访问者实现类,实现要真正被添加到对象结构中的功能。

    考虑这样一个应用:已知三点坐标,编写功能类,求该三角形的面积和周长。

    如果采用访问者模式,应当这样思考:目前已确定的需求分析是求面积和周长功能,但有可能将来求三角形的重心、垂心坐标,内切、外界圆的半径等,因此,在设计时必须考虑如何屏蔽这些不确定情况。具体代码如下。

    1.定义抽象需求分析接口IShape

    interface IShape{
        float getArea();             //明确的需求分析
        float getLength();           //明确的需求分析
        Object accept(IVisitor v);   //可扩展的需求分析
    }
    

    着重理解可扩展的需求分析方法accept(),它在形式上仅是一个方法,但是按访问者模式而言,它却可以表示将来可以求重心、垂心坐标等功能,是一对多的关系,因此IVisitor一般来说是接口或抽象类,“多”项功能一定是由IVisitor的子类来实现的。那么为什么返回值是Object类型呢?可以这样理解,例如重心坐标由两个浮点数表示,外接圆半径由一个浮点数表示,为了屏蔽返回值差异,返回值定义成Object,表明可以返回任意对象类型。

    2.定义具体功能实现类Triangle

    class Triangle implements IShape{
        float x1, y1, x2, y2, x3, y3;           //三角形三点坐标
        public Triangle(float x1, float y1, float x2, float y2, float x3, float y3){
    
            this.x1=x1; this.y1=y1;
            this.x2=x2; this.y2=y2;
            this.x3=x3; this.y3=y3;
        }
        public float getDist(float u1, float v1, float u2, float v2){   //求任意两点距离
            return (float)Math.sqrt((u1-u2)*(u1-u2)+(v1-v2)*(v1-v2));
        }
        public float getArea(){            //固定需求分析求面积
            float a = getDist(x1, y1, x2, y2);
            float b = getDist(x1, y1, x3, y3);
            float c = getDist(x2, y2, x3, y3);
            float s = (a+b+c)/2;
            return (float)Math.sqrt(s*(s-a)*(s-b)*(s-c)); //海伦公式求面积
        }
        public float getLength(){          //固定需求分析求周长
            float a = getDist(x1, y1, x2, y2);
            float b = getDist(x1, y1, x3, y3);
            float c = getDist(x2, y2, x3, y3);
            return a+b+c;
        }
        public Object accept(IVisitor v){  //可扩展需求分析
            return v.visit(this);
        }
    }
    

    着重理解accept()方法,可以看出IVisitor接口中一定定义了多态方法visit(),那为什么把this引用传过去呢?可以这样理解:例如求三角形重心坐标,它的功能一定是在IVisitor的子类实现的,那么该子类一定得知道三角形的三个顶点坐标,因此把this引用传过去,相当于IVisitor的子类可访问Triangle类的成员变量,编制求重心坐标就容易了。

    3.定义访问者接口IVisitor

    interface IVisitor{
        Object visit(Triangle t);
    }
    

    至此为止,有了1、2、3的代码,访问者模式的代码框架就已经构建起来了。如果需求分析没有变化,那么程序一直应用即可;如果需求分析发生变化,则基础功能类不用变化,只要定义IVisitor接口的具体功能实现类就可以了,例如求三角形重心坐标代码如下。
    4.定义重心坐标实现类CenterVisitor

    class Point{
        float x, y;
    }
    class CenterVisitor implements IVisitor{
        public Object visit(Triangle t){
            Point pt = new Point();
            pt.x = (t.x1+t.x2+t.x3)/3;
            pt.y = (t.y1+t.y2+t.y3)/3;
            return pt;
        }
    }
    

    一个简单的测试类如下。

    public class Test3 {
        public static void main(String[] args) {
            IVisitor v = new CenterVisitor();        //定义求重心具体访问者对象
            Triangle t = new Triangle(0,0,2,0,0,2);  //定义三角形对象
            Point pt = (Point)t.accept(v);           //通过访问者对象求三角形重心坐标
            System.out.println(pt.x+"\t"+pt.y);
        }
    }
    

    可以知道,如果再想增加一个求三角形外接圆半径功能,只需再定义一个新类实现IVisitor接口,在该类中完成求外接圆半径功能即可。

    8.命令模式

    顾名思义,命令模式一定是有命令发送者、命令接收者。命令发送者负责发送命令,命令接收者负责接收命令并完成具体的工作。

    命令模式主要针对需要执行的任务或用户提出的请求进行封装与抽象。抽象的命令接口描述了任务或请求的共同特征,而实现则交由不同的具体命令对象完成。每个命令对象都是独立的,它负责完成需要执行的任务,却并不关心是谁调用它。

    命令模式抽象UML类图
    在这里插入图片描述
    命令模式一般有4种角色,如下所示。
    ● ICommander:抽象命令者,是一个接口,规定了用来封装请求的若干个方法。
    ● ConcreteCommander:具体命令发送者,即命令源。它是实现命令接口的类的示例,如上文中的Teacher类。
    ● Invoker:请求者,具体命令的管理与维护类。请求者是一个包含“命令接口”变量的类的示例。请求者中的“命令”接口的变量可以存放任何具体命令的引用,请求者负责调用具体命令,让具体命令执行那些封装了请求的方法。
    ● Receiver:命令接收者,是一个类的示例。该示例负责执行与请求相关的操作,如上文中的Student类。

    考虑老师通知学生打扫卫生的程序描述,具体代码如下。
    1.抽象命令接口ICommand

    interface ICommand{
        public void sweep();
    }
    

    2.命令接收者Student

    class Student{
        public void sweeping(){
            System.out.println("we are sweeping the floor");
        }
    }
    

    在命令模式中,具体工作一定是在接收者中完成的,这一点非常重要。示例中“清扫”工作是由sweeping()方法完成的。
    3.命令发送者Teacher

    class Teacher implements ICommand{
        private Student receiver = null;
        public Teacher(Student receiver){
            this.receiver = receiver;
        }
        public void sweep(){  //发送sweep清扫命令
            receiver.sweeping();
        }
    }
    

    命令发送者类中,一般来说包含命令接收者的引用,表明发送命令的目的地址。所以Teacher类中定义了接收者Student类对象的引用。而实现的抽象接口方法中表明发送命令的具体过程,sweep()中利用方法转发说明具体的清扫工作是由接收者Student对象完成的。
    4.命令请求者类Invoke

    class Invoke{
        ICommand command;
        public Invoke(ICommand command){
            this.command = command;
        }
        public void execute(){
            command.sweep();  //启动命令
        }
    }    
    

    在这里插入图片描述
    在这里插入图片描述
    普通思路是命令发送者直接作用命令接收者,而命令模式思路是在两者之间增加一个请求者类,命令发送者与请求者作用,请求者再与命令接收者作用,请求者起到了一个桥梁的作用

    5.一个简单的测试类

    public class Test {
        public static void main(String[] args)
        {
            Student s = new Student();         //定义接收者
            Teacher t = new Teacher(s);        //定义命令发送者
            Invoke invoke = new Invoke(t);     //将命令请求加到请求者对象中
            invoke.execute();                  //由请求者发送命令
        }
    }
    

    9.装饰器模式

    装饰器模式利用包含代替继承,动态地给一个对象添加一些额外的功能。以消息日志功能为例,其装饰器模式UML类图如图所示
    在这里插入图片描述
    装饰器模式主要有如下4种角色。
    ● 抽象构件角色(Component):
    它是一个接口,封装了将要实现的方法,如ILogger。
    ● 具体构件角色(ConcreteComponent):
    它是多个类,该类实现了Component接口,如FileLogger、ConsoleLogger。
    ● 装饰角色(Decorator):
    它是一个抽象类,该类也实现了Component接口,同时也必须持有接口Component的对象的引用,如事例中Decorator。
    ● 具体的装饰角色(Decorator类的子类,可以有一个,也可以有多个):
    这些类继承了类Decorator,实现了Component接口,描述了具体的装饰过程,如UpLogger、XMLLogger。

    1.抽象装饰器基类Decorator

    abstract class Decorator implements ILogger{
        protected ILogger logger;
        public Decorator(ILogger logger){
            this.logger = logger;
        }
    }
    

    2.具体装饰类

    //信息大写装饰类UpLogger
    class UpLogger extends Decorator{
        public UpLogger(ILogger logger){
            super(logger);
        }
        public void log(String msg) {
            msg = msg.toUpperCase();     //对字符串进行大写装饰
            logger.log(msg);             //再执行已有的日志功能
        }
    }
    
        //XML格式化装饰类XMLLogger
        class XMLLogger extends Decorator{
              public XMLLogger(ILogger logger){
                  super(logger);
              }
              public void log(String msg) {
                  String s = "<msg>\r\n" +
                           "<content>"+msg+"</content>\r\n"+
                            "<time>" + new Date().toString()+ "</time>\r\n"+
                            "</msg>\r\n";
                  logger.log(s);
             }
         }
    

    3.一个简单的测试类

    public class Test {
        public static void main(String[] args)throws Exception {
            ILogger existobj = new FileLogger();     //已有的日志功能
            ILogger newobj= new XMLLogger(existobj); //新的日志装饰类,对existobj装饰
            String s[] = {"how", "are", "you"};        //仿真传送的字符串信息数组
            for(int i=0; i<s.length; i++){
                newobj.log(s[i]);
                Thread.sleep(1000);                  //每隔1 s传送一个新的字符串
            }
            System.out.println("End");
        }
    }
    

    10.组合模式

    文件树型结构示例图
    在这里插入图片描述
    根目录是由两个子目录组成的,第一级子目录由两个文件组成,第二级子目录由两个文件组成,因此树型形式也可以称作组合形式。把叶子节点与目录节点都看成相同性质的节点,只不过目录节点后继节点不为空,而叶子节点后继节点为null。这样就能够对树型结构的所有节点执行相同的操作,这也是组合模式的最大特点。采用组合模式实现文件树型结构的功能,具体代码如下。

    1.定义抽象节点类Node

    abstract class Node{
        protected String name;
        public Node(String name){
            this.name = name;
        }
        public void addNode(Node node)throws Exception{
            throw new Exception("Invalid exception");
        }
        abstract void display();
    }
    

    该类是叶子节点与目录节点的父类,节点名称是name。其主要包括两类方法:一类方法是所有节点具有相同形式、不同内容的方法,这类方法要定义成抽象方法,如display();另一类方法是目录节点必须重写,叶子节点无需重写的方法,相当于为叶子节点提供了默认实现,如addNode()方法,因为叶子对象没有该功能,所以可以通过抛出异常防止叶子节点无效调用该方法。

    2.文件叶子节点类FileNode

    class FileNode extends Node{
        public FileNode(String name){
            super(name);
        }
        public void display(){
            System.out.println(name);
        }
    }
    

    该类是Node的派生类,仅重写display()方法即可。

    3.目录节点类DirectNode

    class DirectNode extends Node{
        ArrayList<Node> nodeList = new ArrayList();
        public DirectNode(String name){
            super(name);
        }
        public void addNode(Node node)throws Exception{
            nodeList.add(node);
        }
        public void display(){
    
            System.out.println(name);
            for(int i=0; i<nodeList.size(); i++){
                nodeList.get(i).display();
            }
        }
    }
    

    该类从Node抽象类派生后,与原DirectNode类相比,主要有以下不同:①由定义两个集合类成员变量转为定义一个集合类成员变量nodeList; ②由定义两个添加方法转为定义一个添加方法addNode(); ③display()方法中,由两个不同元素的循环转为一个对相同性质节点Node的循环。也就是说,原DirectNode中不论是定义成员变量、成员方法,还是方法内部的功能,都要实时考虑叶子节点、目录节点的不同性,因此它的各种定义一定是双份的。而组合模式中认为叶子节点、目录节点是同一性质的节点,因此与原DirectNode类对比,它的各种定义工作一定是减半的,也易于扩充。

    4.一个简单的测试类

    public class Test {
        public static void createTree(Node node)throws Exception{
            File f = new File(node.name);
            File f2[] = f.listFiles();
            for(int i=0; i<f2.length; i++){
                if(f2[i].isFile()){
                    Node node2 = new FileNode(f2[i].getAbsolutePath());
                    node.addNode(node2);
                }
                if(f2[i].isDirectory()){
                    Node node2 = new DirectNode(f2[i].getAbsolutePath());
                    node.addNode(node2);
                    createTree(node2);
                }
            }
        }
        public static void main(String[] args)throws Exception {
            Node start = new DirectNode("d://data");
            createTree(start);
            start.display();
        }
    }
    

    通过该示例,可得组合模式更一般的UML类图,如图所示。共包括以下三种角色。
    在这里插入图片描述
    ● 抽象节点:Node,是一个抽象类(或接口),定义了个体对象和组合对象需要实现的关于操作其子节点的方法,如add()、remove()、display()等。
    ● 叶节点:Leaf,从抽象节点Node派生,由于本身无后继节点,其add()等方法利用Node抽象类中相应的默认实现即可,只需实现与自身相关的remove()、display()等方法即可。
    ● 组合节点:Component,从抽象节点Node派生,包含其他Composite节点或Leaf节点的引用。
    总之,若某应用可形成树型结构,而且形成树型结构后可对叶节点及中间节点进行统一的操作,那么采用组合模式构建应用功能是一个比较好的选择。

    资料来自《Java设计模式深入研究》

    展开全文
  • 主要介绍了Java设计模式单例模式(Singleton)用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • Java和Android源码设计模式,目录:前言,迈出从3K到1W的重要一步——掌握设计模式设计模式中类的关系,谈一谈自己对依赖、关联、聚合和组合之间区别的理解,设计模式六大原则,单一职责原则,里氏替换原则,依赖...
  • 当系统准备为用户提供某个类的子类的实例,又不想让用户代码和该子类形成耦合时,就可以使用...工厂方法模式的关键是在一个接口或抽象类中定义一个抽象方法,下面我们会具体介绍Java使用设计模式中的工厂方法模式实例解析.
  • 1.设计模式七大原则 单一职责原则 接口隔离原则 依赖倒转(倒置)原则 里氏替换原则 开闭原则 迪米特法则 合成复用原则 1.1.单一职责原则 1.1.1.基本介绍 一个类只应负责一项职责。 1.1.2.应用实例 package ...
  • 该密码管理器应用由Java语言编写,使用了GUI框架Swing,以MySQL5.7作为后台数据库管理系统进行开发。在该密码管理器的开发中,我们...文件里有代码,类图,开发报告(包括需求分析,系统设计代码详解,软件测试。)
  • 《软件设计模式Java版)》(ISBN:978-7-115-47788-0,人民邮电出版社)是一本好书,它是软件开发者的必备工具书,也是计算机相关专业必选的教学用书。其电子课件PPT、程序源代码、各章的习题答案等相关资源的下载...
  • Sunny在CSDN技术博客中陆续发表了100多篇与设计模式学习相关的文章,涵盖了七个面向对象设计原则和24个设计模式(23个GoF设计模式 + 简单工厂模式),为了方便大家学习, 现将所有文章的进行了整理,方便大家下载...
  • 主要介绍了Java设计模式模板方法模式(Template)用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 设计模式解析

    2018-11-28 16:10:36
    想要学好java必须懂得的设计模式,可提升自己的开发能力,提升代码的质量

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 370,811
精华内容 148,324
关键字:

java设计模式代码分析

java 订阅