精华内容
下载资源
问答
  • 26种设计模式大全(含java代码) /**  * 适配器模式  * 在计算机编程中,适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的。  * 一个适配允许通常因为接口不兼容而不能在一起...
    26种设计模式大全(含java代码)


    /**
     * 适配器模式
     * 在计算机编程中,适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的。
     * 一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。
     *
     */
     
     
     
     /**
     *  桥接模式
     *  在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?这就要使用桥接模式
     *
     */
     
     
     /**
     * 建造者模式 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 
     * 1 builder:为创建一个产品对象的各个部件指定抽象接口。
     * 2 ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并 提供一个检索产品的接口。 3
     *    Director:构造一个使用Builder接口的对象。 4
     * Product:表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程
     * 包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
     */
     
     
     /*
     *
     * 命令模式 “行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,
     * 这种无法抵御变化的紧耦合是不合适的。
     * 在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式(Command Pattern)
     * 
     * 1.降低对象之间的耦合度。 2.新的命令可以很容易地加入到系统中。 3.可以比较容易地设计一个组合命令。 4.调用同一方法实现不同的功能
     * 
     */
     
     
     
     /*
     *
     * 组合模式 组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
     * 有时候又叫做部分-整体模式,
     * 它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
     * 组合模式让你可以优化处理递归或分级数据结构
     * 。有许多关于分级数据结构的例子,使得组合模式非常有用武之地。关于分级数据结构的一个普遍性的例子是你每次使用电脑时所遇到的
     * :文件系统。文件系统由目录和文件组成
     * 。每个目录都可以装内容。目录的内容可以是文件,也可以是目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构
     * ,那么你可以使用组合模式Composite。
     */
     
     
     /**
     * 组合模式 组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
     * 有时候又叫做部分-整体模式,
     * 它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
     * 组合模式让你可以优化处理递归或分级数据结构
     * 。有许多关于分级数据结构的例子,使得组合模式非常有用武之地。关于分级数据结构的一个普遍性的例子是你每次使用电脑时所遇到的
     * :文件系统。文件系统由目录和文件组成
     * 。每个目录都可以装内容。目录的内容可以是文件,也可以是目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构
     * ,那么你可以使用组合模式Composite。
     */
     
     
     
     /*
     *
     *装饰模式
     *装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
     */
     
     
     
     /**
     * 解释器模式 意图:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。
     * 主要解决:对于一些固定文法构建一个解释句子的解释器。
     * 何时使用:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子
     * 。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。 如何解决:构件语法树,定义终结符与非终结符。
     */
     
     
     
     /**
     * 解释器模式 意图:给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。
     * 主要解决:对于一些固定文法构建一个解释句子的解释器。
     * 何时使用:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子
     * 。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。 如何解决:构件语法树,定义终结符与非终结符。
     */
     
     
     /**
     * 外观模式
     * 外观模式(Facade),为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用。
     *
     */
     
     
     /**
     * 工厂模式 工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。
     * 著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A
     * a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,
     * 但会给你系统带来更大的可扩展性和尽量少的修改量。
     */
     
     
     
     /**
     * 工厂模式 工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。著名的Jive论坛
     * ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A
     * a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,
     * 但会给你系统带来更大的可扩展性和尽量少的修改量。
     */
     
     /**
     * 享元模式
     * 
     * 它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件。
     * 通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。
     * 如果一个应用程序使用了大量的对象,而这些对象造成了很大的存储开销的时候就可以考虑是否可以使用享元模式。
     * 例如,如果发现某个对象的生成了大量细粒度的实例,并且这些实例除了几个参数外基本是相同的
     * ,如果把那些共享参数移到类外面,在方法调用时将他们传递进来,就可以通过共享大幅度单个实例的数目。
     */
     
     
     /**
     * 责任链模式
     * 
     * 责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。
     * 发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
     * 
     */
     
     
     
     
     /**
     * 责任链模式
     * 
     * 责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。
     * 发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
     * 
     */
     
     
     
     /**
     * 中介者模式 Mediator模式也叫中介者模式,是由GoF提出的23种软件设计模式的一种。Mediator模式是行为模式之一,在Mediator模式中,
     * 类之间的交互行为被统一放在Mediator的对象中,对象通过Mediator对象同其他对象交互,Mediator对象起着控制器的作用。
     * 
     */
     
     
     /**
     * 备忘录模式 
     * 在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
     */
     
     
     
     
     /**
     * 观察者模式
     * 一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。
     * 此种模式通常被用来实现事件处理系统。
     */
     
     
     
     /**
     * 观察者模式
     * 一个目标物件管理所有相依于它的观察者物件,
     并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。
     * 此种模式通常被用来实现事件处理系统。
     */
     
     
     /**
     * 原型模式
     * 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
     */
     
     
     /**
     * 代理模式 
     * 真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
     * (2).代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。 (3).高扩展性
     */
     
     
     
     
     /**
     * 抽象工厂模式 抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。
     * 抽象工厂模式可以向客户端提供一个接口
     * ,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据里氏替换原则,任何接受父类型的地方,都应当能够接受子类型
     * 。因此,实际上系统所需要的,
     * 仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。
     */
     
     
     
     
     /**
     * 抽象工厂模式 抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。
     * 抽象工厂模式可以向客户端提供一个接口
     * ,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据里氏替换原则,任何接受父类型的地方,都应当能够接受子类型
     * 。因此,实际上系统所需要的,
     * 仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。
     */
     
     
     
     /**
     * 单例模式
     *单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例
     */
     
     
     /**
     * 状态模式
     * 状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
     */
     
     
     
     /**
     *策略模式 
     *策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
     */
     
     
     
     /**
     * 模板模式
     *  模板方法模式(Template Method
     * Pattern),定义一个操作中的算法骨架,而将一些实现步骤延迟到子类当中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
     * 模板方法模式是比较简单的一种设计模式
     * ,但是它却是代码复用的一项基本的技术,在类库中尤其重要,它遵循“抽象类应当拥有尽可能多的行为,应当拥有尽可能少的数据”的重构原则
     * 。作为模板的方法要定义在父类中,在方法的定义中使用到抽象方法,而只看父类的抽象方法是根本不知道怎样处理的,实际做具体处理的是子类,在子类中实现具体功能,
     * 因此不同的子类执行将会得出不同的实现结果,但是处理流程还是按照父类定制的方式。这就是模板方法的要义所在,制定算法骨架,让子类具体实现。
     */
     
     
     
     
     /**
     * 访问者模式
     * 
     * 1.Visitor 抽象访问者角色,为该对象结构中具体元素角色声明一个访问操作接口。该操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色,
     * 这样访问者就可以通过该元素角色的特定接口直接访问它。 2.ConcreteVisitor.具体访问者角色,实现Visitor声明的接口。
     * 3.Element 定义一个接受访问操作(accept()),它以一个访问者(Visitor)作为参数。
     * 4.ConcreteElement具体元素,实现了抽象元素(Element)所定义的接受操作接口。
     * 5.ObjectStructure结构对象角色,这是使用访问者模式必备的角色。它具备以下特性
     * 能枚举它的元素;可以提供一个高层接口以允许访问者访问它的元素;如有需要,可以设计成一个复合对象或者一个聚集(如一个列表或无序集合)。
     * 
     * 1、 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
     * 2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor模式使得你可以将相关的操作集中起来定义在一个类中。 
     * 3、 当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
     * 4、定义对象结构的类很少改变,但经常需要在此结构上定义新的操作
     * 。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
     */
     
     
     
    展开全文
  • 23种设计模式java实例代码之装饰模式

      

    装饰模式

    说明:

    装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

    装饰模式的特点;

    (1) 装饰对象和真实对象有相同的接口。这样客户端对象就可以以和真实对象相同的方式和装饰对象交互。
    (2) 装饰对象包含一个真实对象的索引(reference)
    (3) 装饰对象接受所有的来自客户端的请求。它把这些请求转发给真实的对象。
    (4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

    下表格列举了装饰模式和继承的不同:

    装饰模式 VS 继承

    装饰模式 继承
    用来扩展特定对象的功能 用来扩展一类对象的功能
    不需要子类 需要子类
    动态地 静态地
    运行时分配职责 编译时分派职责
    防止由于子类而导致的复杂和混乱 导致很多子类产生,在一些场合,报漏类的层次
    更多的灵活性 缺乏灵活性
    对于一个给定的对象,同时可能有不同的装饰对象,客户端可以通过它的需要选择合适的装饰对象发送消息。 对于所有可能的联合,客户期望
    很容易增加任何的 困难

     

     

    装饰模式-JAVA代码实现

     

     

    新建一个抽象汽车父类:新建一个抽象汽车父类:

     

    package car_package;
    public abstract class
     car_parent {
        
    // 汽车抽象父类

        private String make_address;
        
    private int
     speed;
        
    public
     String getMake_address() {
            
    return
     make_address;
        }
        
    public void
     setMake_address(String make_address) {
            
    this.make_address =
     make_address;
        }
        
    public int
     getSpeed() {
            
    return
     speed;
        }
        
    public void setSpeed(int
     speed) {
            
    this.speed =
     speed;
        }
        
    public abstract void
     print_face();
    }

     

     

    然后新建一个奥迪汽车子类

     

    package car_package;
    public class audi_sub extends
     car_parent {
        
    // 奥迪汽车子类

        @Override
        
    public void print_face() {
            System.out.println(
    "audi车默认的颜色为 黑色"
    );
        }
    }

     

     

     然后再新建一个装饰者父类:

     

    package decorator_package;
    import
     car_package.car_parent;
    public abstract class decorator_parent extends
     car_parent {
        
    // 装饰者父类

        
    protected car_parent car_parent_ref;
        
    public void
     setCar_parent_ref(car_parent car_parent_ref) {
            
    this.car_parent_ref =
     car_parent_ref;
        }
        @Override
        
    public void
     print_face() {
            car_parent_ref.print_face();
        }
    }

     

     

     然后再新建装饰者子类:红色火焰装饰者类:

    package decorator_package;
    public class decorator_audi_red extends
     decorator_parent {
        @Override
        
    public void
     print_face() {
            
    super
    .print_face();
            System.out.println(
    "给 奥迪 喷涂鸦 - 颜色为 红色火焰"
    );
        }
    }

     

     

    然后再新建装饰者子类:紫色霞光装饰者类:

     

    package decorator_package;
    public class decorator_audi_purple extends
     decorator_parent {
        @Override
        
    public void
     print_face() {
            
    super
    .print_face();
            System.out.println(
    "给 奥迪 喷涂鸦 - 颜色为 紫色霞光"
    );
        }
    }

     

     

    新建一个运行类

     

    package main_run;

    import
     car_package.audi_sub;
    import
     decorator_package.decorator_audi_purple;
    import
     decorator_package.decorator_audi_red;

    public class
     main_run {

        
    public static void
     main(String[] args) {

            audi_sub audi_sub_ref 
    = new
     audi_sub();
            audi_sub_ref.setMake_address(
    "北京市朝阳区"
    );
            audi_sub_ref.setSpeed(
    200
    );

            decorator_audi_red decorator_audi_red_ref 
    = new
     decorator_audi_red();
            decorator_audi_red_ref.setCar_parent_ref(audi_sub_ref);

            decorator_audi_purple decorator_audi_purple_ref 
    = new
     decorator_audi_purple();
            decorator_audi_purple_ref.setCar_parent_ref(decorator_audi_red_ref);

            decorator_audi_purple_ref.print_face();
        }
    }

     

     程序运行结果如下:

     

    audi车默认的颜色为 黑色
    给 奥迪 喷涂鸦 
    -
     颜色为 红色火焰
    给 奥迪 喷涂鸦 
    - 颜色为 紫色霞光

        audi车默认的颜色为 黑色
    给 奥迪 喷涂鸦 
    -
     颜色为 红色火焰
    给 奥迪 喷涂鸦 
    - 颜色为 紫色霞光
    展开全文
  • Java 23种设计模式

    千次阅读 2016-01-04 18:40:36
    Java 23种设计模式 1. 设计模式…… 2. 设计模式分类…… 3. 6大设计原则…… 4. 23种设计模式……


    Java 23种设计模式

    文 | 莫若吻


    注:以下内容是个人通过查找资料学习总结整理得出的概念性的知识,若有问题,请留言。谢谢!

    1. 设计模式

    设计模式(Design pattern)是软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。

    它是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式并不直接用来完成代码的编写,而是描述在各种不同情况下,要怎么解决问题的一种方案面向对象设计模式通常以对象来描述其中的关系和相互作用,但不涉及用来完成应用程序的特定类或对象。设计模式能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免会引起麻烦的紧耦合,以增强软件设计面对并适应变化的能力。并非所有的软件模式都是设计模式,设计模式特指软件“设计”层次上的问题。还有其它非设计模式的模式,如架构模式。同时,算法不能算是一种设计模式,因为算法主要是用来解决计算上的问题,而非设计上的问题。


    2. 设计模式分类

    设计模式分为创建型模式、结构型模式、行为型模式三大类,主要通过授权、聚合、诊断的概念来描述。

    对象层面:处理对象之间的关系,决定于运行期。
    类层面:处理类的关系,决定于在编译期。

    1)创建模式:是关于如何创建实例的。用来构建对象以便能从实现系统解耦。

    可以被划分为两组:类创建实例、对象创建实例。

    类创建实例在实例化过程中有效的使用类之间的继承关系,对象创建实例则使用代理来完成其任务。

    共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式/构造器模式、原型模式。


    2)结构模式:关于类及对象复合关系的。用不同的对象组成大规模的对象结构。

    共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

    3)行为模式:关于对象之间如何通讯的。用来在对象中管理算法、关系和责任。

    共十一种:策略模式、模板方法模式、观察者模式、迭代器模式、

    责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。


    其实还有两类:并发型模式和线程池模式(这里不作深入解析)。


    3. 6大设计原则

    单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特法则、开闭原则。

    设计原则上需遵循这两点:第一,识别你的应用程序里不稳定的部分,并且把它们与稳定的部分隔离开。
    第二,面向接口而不是面向实现编程。

    Note:不要为了套用原则而做项目。

    总结:

    单一职责原则告诉我们实现类要职责单一;

    里氏替换原则告诉我们不要破坏继承体系;

    依赖倒置原则告诉我们要面向接口编程;

    接口隔离原则告诉我们在设计接口的时候要精简单一;

    迪米特法则告诉我们要降低耦合。

    开闭原则是总纲,告诉我们要对扩展开放,对修改关闭。


    1)单一职责原则

    单一职责原则:SRPSingle Responsibility Principle)。应该有且仅有一个原因引起类的变更。实际中比较不好把握,因为职责的划分没有一个统一的标准。

    优点:

    • 可以降低类的复杂性;
    • 提高类的可读性,提高系统的可维护性;
    • 降低了变更引起的风险。

    Note:变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。

    NoteSRP适用于接口、类,也适用于方法(即:一个接口一定要做到单一职责。一个类只负责一项职责,类的设计尽量做到只有一个原因引起变化。一个方法尽可能去做一件事。)

    单一职责原则(SRP)提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或类设计得是否优良,但是“职责”和“变化原因”都是不可度量的,因项目而异,因环境而异,在实际开发中可能会违背SRP。


    2)里氏替换原则

    里氏替换原则:LSPLiskov Substitution Principle)。子类可以扩展父类的功能,但不能改变父类原有的功能。(简单地讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但反过来,有子类出现的地方,父类未必就能适应。)

    定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。

    定义2:所有引用基类的地方必须能透明地使用其子类的对象。

    LSP 优点:

    • 代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;
    • 提高代码的重用性;
    • 子类可以形似父类,但又异于父类,“龙生龙,凤生凤,老鼠生来会打洞”是说子拥有父的“种”,“世界上没有两片完全相同的叶子”是指明子和父的不同;
    • 提高代码的可扩展性,实现父类的方法就可以“为所欲为”了,可以看到很多开源框架的扩展接口都是通过继承父类来完成的;
    • 提高产品或项目的开放性;

    继承的缺点:

    • 继承是浸入性的。只要继承,就必须拥有父类的所有属性和方法;
    • 降低代码的灵活性。子类必须拥有父类的所有属性和方法,让子类自由的世界中多了些约束;
    • 增强了耦合性。当父类的常量、变量和方法被修改时,必须要考虑子类的修改,而且是在缺乏规范的环境下,这种修改可能带来非常糟糕的结果----大片代码需要重构。

    Note:如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承。里氏替换原则可以正着用,但是不能反着用,在子类出现的地方,父类未必就可以胜任。

    为了减少继承所带来的弊端,才出现了里氏替换原则。

    里氏替换原则为良好的继承定义了一个规范:

    • 子类必须完全实现父类的方法;(子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
    • 子类中可以增加自己特有的方法。;
    • 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
    • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。


    3)依赖倒置原则

    依赖倒置原则:DIPDependence Inversion Principle)。高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。

    DIP的核心思想是面向接口编程。DIP是实现开闭原则的重要途径。

    在Java语言中的表达就是,模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;接口或抽象类不依赖于实现类;实现类依赖接口或抽象类。

    Note相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。在java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。

    传递依赖关系有三种方式:接口传递、构造方法传递和setter方法传递。只要做到抽象依赖,即时是多层的依赖关系也无所畏惧。

    DIP在实际编程中,一般需要做到如下3点:

    • 低层模块尽量都要有抽象类或接口,或者两者都有。
    • 变量的声明类型尽量是抽象类或接口。
    • 使用继承时遵循里氏替换原则。

    DIP的优点:

    依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性。

    要遵循DIP,在项目开发中需要遵循的原则应该有:

    • 每一个类尽量都有接口或抽象类,或者抽象类和接口两者都具备;
    • 变量的表面类型尽量都是接口或是抽象类;
    • 任何类都不应该从具体类派生(只要不超过两层的继承都是可以接受的,特别是负责项目维护的同志,基本上可以不考虑这个原则);
    • 尽量不要复写基类的方法
    • 结合里氏替换原则使用;

    Note:接口负责定义public属性和方法,并声明与其他对象的依赖关系;抽象类负责公共构造部分的实现;实现类实现业务逻辑,同时再适当时对父类进行细化。

    4)接口隔离原则

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

    接口隔离原则是对接口进行规范约束。建立单一接口,不要建立臃肿庞大的接口,接口尽量细化,同时接口中的方法尽量少。客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。 

    ISP与SRP的区别:

    其一,单一职责原则原注重的是职责,这是业务逻辑上的划分;而接口隔离原则注重对接口依赖的隔离,要求接口的方法尽量少

    其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口,主要针对抽象,针对程序整体框架的构建。

    eg:一个接口的职责可能包含10个方法,这10个方法都放在一个接口中,并且提供给多个模块访问,各个模块按照规定的权限来访问,在系统外通过文档约束“不使用的方法不要访问”,按照单一职责原则是允许的,按照接口隔离原则是不允许的,因为它要求“尽量使用多个专门的接口”。

    接口隔离原则是对接口进行规范约束,注意保证接口的纯洁性,如下:

    • 接口要尽量小,根据接口隔离原则拆分接口时,首先必须满足单一职责原则;
    • 接口要高内聚,高内聚就是提高接口、类、模块的处理能力,减少对外的交互,要求在接口中尽量少公布public方法,接口是对外的承诺,承诺是对外的承诺,承诺越少对系统的开发越有利,变更的风险也就越少,同时也有利于降低成本;
    • 定制服务,即单独为一个个体提供优良的服务,要求只提供访问者需要的方法;
    • 接口的设计是有限度的;

    Note:运用接口隔离原则,一定要适度。

    接口隔离原则是对接口的定义,同时也是对类的定义,接口和类尽量使用原子接口或原子类来组装。

    如何划分原子?

    • 一个接口只服务于一个子模块或业务逻辑。
    • 通过业务逻辑压缩接口中的public方法(尽量使接口简洁)。
    • 已经被污染的接口尽量去修改,若变更风险较大,则采用适配器模式进行转化处理。
    • 了解环境,拒绝盲从。(尽量不copy他人代码,毕竟实际应用环境不同,逻辑不同)

    5)迪米特法则

    迪米特法则:LoD(Law of Demeter),也是最小知识原则(Least Knowledge Principle)LKP。一个对象应该对其他对象有最少的了解。

    迪米特法则的核心观念就是类间解耦、弱耦合,但解耦是有限度的。

    理解:一个类应该对自己需要耦合或调用的类知道得最少,你(被耦合或调用的类)的内部是如何复杂都和我没关系,那是你的事情,我就知道你提供的这么多public方法,我就调用这么多,其他的我一概不关心。

    当类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大时,尽量降低类与类之间的耦合。

    LoD对类的低耦合提出了明确要求:

    • 只和“朋友”交流。即:出现在成员变量、方法的输入输出参数中的类为“朋友”,而出现在方法体内部的类不属于“朋友”。
    • “朋友”间也是有距离的。

    一个public属性或方法越多,修改涉及面越大,变更风险扩散越大。因此在设计时需反复衡量:

    是否还可以再减少public方法和属性。

    是否可修改private、package-private、protected等访问权限。(package-private:包类型,在类、方法、变量前不加访问权限,则默认为包类型

    是否可加final关键字等

    Note:迪米特法则要求类尽量不对外公布太多public方法和非晶态的public变量,多使用private、package-private、protected等访问权限。

    • 自己就是自己的。

    在实际开发中,一个方法可放在本类中,也可放在其他类中。此时坚持一个原则:如果方法放在本类中既不增加类间关系,也对本类不产生负面影响,就放在本类中。

    • 谨慎使用Serializable。(情况比较少见)

    eg:客户端与服务器连接,需写接口,把网络传输的对象进行序列化,否则会报NotSerializableException异常。若有一天,客户端修改了一个接口参数的访问权限,从private变为public,访问权限变大,而服务器段并没有作相应更新,就会报序列化失败。

    6)开闭原则

    开闭原则:OCP(Open Closed Principle)。软件实体(eg:类、模块、函数)应该对扩展开放,对修改关闭。

    (即:一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。)

    软件实体包括:1--项目或软件产品中按照一定的逻辑规划的模块。2--抽象。3--方法

    开闭原则是Java中最基础的设计原则。

    解析:用抽象构建框架,用实现扩展细节。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了。当然前提是我们的抽象要合理,要对需求的变更有前瞻性和预见性才行。

    开闭原则是一个非常虚的原则,前5个原则是对开闭原则的具体解释,但开闭原则并不局限这么多。

    我们遵循设计模式前面5大原则,以及使用23种设计模式的目的就是遵循开闭原则。

    Note:开闭原则并不意味着不做任何修改,低层模块的变化,必然有高层模块进行耦合,否则就是一段孤立无意义的代码。

    变化归纳为三种:

    • 逻辑变化只变化一个逻辑而不涉及其他模块。
    • 子模块变化一个模块变化,会对其他模块产生影响,
    • 可见视图变化提供给客户使用的视图界面。

    开闭原则的重要性:

    • 开闭原则对测试有很大的影响(注:若不理解,此处可以参考《设计模式之禅》一书)
    • 提高复用性。
    • 提高可维护性。
    • 开闭原则是面向对象开发的要求。

    开闭原则的使用:

    • 抽象约束。通过接口或抽象类可以约束一组可能变化的行为,并且能够实现对扩展开放。

    通过接口或抽象类约束扩展,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法。

    参数类型、引用对象尽量使用接口或者抽象类,而不是实现类。

    抽象层尽量保持稳定,一旦确定不允许修改。

    • 元数据控制模块行为。

    元数据:用来描述环境和数据的数据,即:配置参数。

    • 制定项目章程。(即项目成员统一遵守的代码规范和约定)
    • 封装变化。

    将相同变化封装到一个接口或抽象类中。

    将不同的变化封装到不同接口或抽象类中,不应有两个不同的变化出现在同一接口或抽象类中。

    4. 23种设计模式

    (注:欲知详情请点击进去查看,未贴出地址的后续都会补充完整。)

    1)创建型模式

    单例模式http://blog.csdn.net/sun_promise/article/details/25536547

    工厂方法模式:

    抽象工厂模式:

    建造者模式:

    原型模式:

    2)结构模式

    适配器模式:

    装饰模式http://blog.csdn.net/sun_promise/article/details/33329671

    代理模式:

    外观模式:

    桥接模式:

    组合模式:

    享元模式:

    3)行为模式

    策略模式:

    模板方法模式http://blog.csdn.net/sun_promise/article/details/25659527

    观察者模式:

    迭代子模式:

    责任链模式:

    命令模式:

    备忘录模式:

    状态模式:

    访问者模式:

    中介者模式:

    解释器模式:




    展开全文
  • Java中23种设计模式的详细介绍

    千次阅读 多人点赞 2019-12-17 10:50:52
    Java开发中23种设计模式详细介绍设计模式介绍设计模式分类设计模式六大原则开闭原则(Open Close Principle)里氏代换原则 设计模式介绍 设计模式(Design Patterns): 一套被反复使用,多数人知晓,经过分类编目,代码...

    设计模式介绍

    • 设计模式(Design Patterns):
      • 一套被反复使用,多数人知晓,经过分类编目,代码设计的总结
      • 使用设计模式是为了可重用代码,让代码更容易理解,保证代码可靠性
    • 项目中合理运用设计模式可以完美的解决很多问题,每种模式都有相应的原理与之对应,
    • 每个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案

    设计模式分类

    • 总体来说,设计模式分为三大类:
      • 创建型模式(5种):
        • 工厂方法模式
        • 抽象工厂模式
        • 单例模式
        • 建造者模式
        • 原型模式
      • 结构型模式(7种):
        • 适配器模式
        • 装饰器模式
        • 代理模式
        • 外观模式
        • 桥接模式
        • 组合模式
        • 享元模式
      • 行为型模式(11种):
        • 策略模式
        • 模板方法模式
        • 观察者模式
        • 迭代子模式
        • 责任链模式
        • 命令模式
        • 备忘录模式
        • 状态模式
        • 访问者模式
        • 中介者模式
        • 解释器模式
    • 其余两类模式:
      • 并发型模式
      • 线程池模式
        -

    设计模式六大原则

    单一职责原则(Single Responsibility Principle) - 这里的设计模式原则,主要讨论的是Java面向对象编程设计中设计原则,单一职责原则由于其适用的普遍性,个人认为不放在六大原则之中

    • 单一职责原则 :一个类只负责一项职责
    • 不能存在多于一个导致类变更的原因
    • 单一职责原则符合"高内聚,低耦合"的思想
    • 单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则

    开闭原则(Open Close Principle)

    • 开闭原则 :对扩展开放,对修改关闭
    • 程序进行扩展的时候,不能修改原有的代码, 实现一个热插拔的效果
    • 为了使程序扩展性好,易于维护和升级:需要使用接口和抽象类

    里氏代换原则(Liskov Substitution Principle)

    • 里氏代换原则 :任何基类可以出现的地方,子类一定可以出现
    • LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受影响时, 基类才能真正被复用,衍生类也能够在基类的基础上增加新的行为
    • 里氏代换原则是对实现抽象化的具体步骤的规范:
      • 里氏代换原则是对开闭原则的补充
      • 实现开闭原则的关键步骤就是抽象化
      • 基类与子类的继承关系就是抽象化的具体实现

    依赖倒转原则(Dependence Inversion Principle)

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

    接口隔离原则(Interface Segregation Principle)

    • 接口隔离原则 :使用多个隔离的接口,比使用单个接口要好,降低类之间的耦合度
    • 从接口隔离原则可以看出:设计模式就是一个软件的设计思想
    • 从大型软件架构出发,为了升级和维护方便 :降低依赖,降低耦合

    迪米特法则(最少知道原则)(Demeter Principle)

    • 迪米特法则:最少知道原则 ,一个实体应当尽量少的与其它实体发生相互作用,使得功能模块相互独立

    合成复用原则(Composite Reuse Principle)

    • 合成复用原则 :尽量使用合成或者聚合的方式,而不是使用继承

    Java中23种设计模式


    创建型模式

    工厂方法模式(Factory Method)

    工厂方法模式分为三种 :普通工厂模式,多个工厂方法模式,静态工厂方法模式

    普通工厂模式
    • 建立一个工厂类,对实现了同一接口的一些类进行实例的创建:
      -
    --- 发送邮件和短信
    - 接口
    public interface Sender{
    	public void Send();
    }
    
    
    
    
    - 实现类
    public class MailSender implements Sender{
    	@Override
    	public void Send(){
    		System.out.println("MailSender Method");
    	}
    }
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    public class SmsSender implements Sender{
    	@Override
    	public void Send(){
    		System.out.println("SmsSender Method");
    	}
    }
    
    
    
    
    - 工厂类
    public class SendFactory{
    	public Sender produce(String type){
    		if("mail".equals(type)){
    			return new MailSender();
    		}else if("sms".equals(type)){
    			return new SmsSender();
    		}else{
    			System.out.println("Please input right type!");
    		}
    	}
    }
    
    
    
    
    - 测试类
    public class FactoryTest{
    	public static void main(String[] args){
    			SendFactory factory=new SendFactory();
    			Sender sender=factory.produce("sms");
    			sender.Send();
    	}
    }
    
    多个工厂方法模式
    • 多个工厂方法模式是对普通工厂方法模式的改进
    • 普通工厂方法模式中,如果传递的字符串出错,则不能创建对象
    • 多个工厂方法模式提供多个工厂方法,分别创建对象
      -
    - SendFactory类
    public class SendFactory{
    		public Sender produceMail(){
    				return new MailSender();
    		}
    
    		public Sender produceSms(){
    				return new SmsSender();
    		}
    }
    
    
    
    
    - 测试类
    public class FactoryTest{
    		public static void main(String[] args){
    				SendFactory factory=new SendFactory();
    				Sender sender=factory.produceMail();
    				sender.Send();
    		}
    }
    
    静态工厂方法模式
    • 多个工厂方法模式中的方法设置为静态方法, 不需要创建实例 ,直接调用即可
    - SendFactory
    public class SendFactory{
    		public static Sender produceMail(){
    				return new MailSender();
    		}
    
    		public static Sender produceSms(){
    				return new SmsSender();
    		}
    }
    
    
    
    
    - FactoryTest
    public class FActoryTest{
    		public static void main(String[] args){
    				Sender sender=SenderFactory.produceMail();
    				sender.Send();
    		}
    }
    
    总结
    • 工厂模式适合出现大量的产品需要创建,并且具有共同的接口,可以通过工厂方法模式创建:
      • 普通工厂模式: 如果传入字符串有误,就不能创建对象
      • 静态工厂方法模式相对于多个工厂方法模式 ,不需要实例化工厂类
      • 大多数情况下,采用静态工厂方法模式

    抽象工厂模式(Abstract Factory)

    • 工厂方法模式问题: 类的创建依赖工厂类.如果想要扩展程序,必须对工厂类进行修改,这违背了闭包原则
    • 抽象工厂模式: 创建多个工厂类,一旦需要增加新的功能,直接增加工厂类就可以,不需要修改之前的工厂类
      -
    - Sender
    public interface Sender{
    		public void Sender();
    }
    
    
    
    - 两个实现类
      - MailSender 
    public class MailSender implements Sender {
    		@Override
    		public void Send(){
    				System.out.println("This is MailSender!");
    		}
    }
    
    
    
      - SmsSender
    public class SmsSender implements Sender{
    		@Override
    		public void Send(){
    				System.out.println("This is SmsSender!");
    		}
    }
    
    
    
    - 两个工厂类
      - 工厂类接口:
    public interface Provider{
    		public Sender produce();
    }
      - SendMailFactory
    public class SendMailFactory implements Provider{
    		@Override
    		public Sender produce(){
    				return new MailSender();
    		}
    }
      - SendSmsFactory
    public class SendSmsFactory implements Provider{
    		@Override
    		public Sender produce(){
    				return new SmsSender();
    		}
    }
    
    
    
    
    - Test
    public class Test{
    		public static void main(String[] args){
    				Provider provider=new SendMailFactory();
    				Sender sender=provider.produce();
    				sender.Send();
    		}
    }
    
    • 抽象工厂模式的优点就是拓展性强:
      • 如果需要增加一个功能,例如:发及时信息
        • 只需做一个实现类, 实现Sender接口
        • 做一个工厂类, 实现Provider接口

    单例模式(Singleton)

    • 单例模式 :保证在一个JVM中,一个单例对象只有一个实例存在
    • 单例模式的优点:
      • 某些类创建比较繁琐,对于一些大型对象,可以减少很大的系统开销
      • 省去了new操作符,降低了系统内存的使用频率,减轻GC(Garbage Collection-垃圾回收)压力
      • 有些类比如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个,系统会完全混乱,所有只有使用单例模式,才能保证核心交易服务器独立控制整个流程
    - 单例类
    public class Singleton{
    		/* 私有静态实例,防止被引用,赋值为null,目的是实现延迟加载 */
    		private static Singleton instance=null;
    
    		/* 私有构造方法,防止被实例化 */
    		private Singleton(){
    		}
    
    		/* 静态工厂方法,创建实例 */
    		public static Singleton getInstance(){
    				if(instance==null){
    						instance=new Singleton();
    				}
    
    				return instance;
    		}
    
    		/* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
    		public Object ReadResolve(){
    				return instance;
    		}
    }
    
    • 考虑到多线程安全,首先会想到对getInstance方法加synchronized关键字:
    public static synchronized Singleton getInstance(){
    		if(instance==null){
    			instance=new Singleton();
    		}
    		return instance;
    }
    

    由于synchronized锁住的是这个对象,这样的用法,每次调用getInstance(),都要对对象上锁,在性能上会有所下降.

    • 只有在第一次创建对象的时候需要加锁,之后就不需要了:
    public static Singleton getInstance(){
    		if(instance==null){
    			synchronized(instance){
    				if(instance==null){
    					instance=new Singleton();
    				}
    			}
    		}
    		return instance;
    }
    

    这样似乎解决了问题,将synchronized关键字加入内部,这样在调用的时候是不需要加锁的,只有在instance为null,并创建对象的时候才需要的加锁,性能得到了提升,但是这样的情况还是有问题的

    • 存在这样的情况:
      • 在Java中创建对象和赋值操作是分开进行的
      • 即instance=new Singleton()是分两步执行的
      • JVM并不保证这两个操作的先后顺序:
        • 有可能JVM会为新的Singleton实例分配空空间,然后直接赋值给instance成员
        • 然后再去初始化这个Singleton实例
      • 这样就可能会出错
    • 示例:
      • A,B两个线程
        • A,B线程同时进入第一个if判断
        • A首先进入synchronized块,由于instancenull, 执行instance=new Singleton()
        • 由于JVM内部的优化机制 ,JVM先划出一些分配给Singleton的空白内存,并赋值给instance成员,此时还没有开始初始化这个实例,然后A离开了synchronized
        • B进入synchronized, 由于instance此时不是null, 因此它马上离开了synchronized块并将结果返回给调用该方法的程序
        • 此时B线程打算使用Singleton实例,发现它还没有初始化,于是产生错误
    • 代码需要进一步优化:
    private static class SingletonFactory{
    	private static Singleton instance=new Singleton();
    }
    
    public static Singleton getInstance(){
    	return SingletonFactory.instance;
    }
    
    • 实际情况是:
      • 单例模式使用内部类来维护单例的实现
      • JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是互斥的
      • 当第一次调用getInstance时,JVM能够保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕
      • 该方法也只会在第一次调用的时候采用互斥机制,可以完美解决低性能的问题
    public class Singleton{
    	/* 私有构造方法,防止被实例化 */
    	private Singleton(){}
    
    	/* 使用内部类维护单例 */
    	private static class SingletonFactory{
    		private static Singleton instance=new Singleton();
    	}
    
    	/* 获取实例 */
    	public static Singleton getInstance(){
    		return SingletonFactory.instance;
    	}
    
    	/* 如果该对象被序列化,可以保证对象在序列化前后保持一致 */
    	public Object readResolve(){
    		return getInstance();
    	}
    }
    

    这种方法,如果在构造函数中抛出异常,实例将永远不会创建,也会出错.
    只能根据实际场景,选择最适合应用场景的实现方法

    • 因为只需要在创建类的时候进行同步,所以只要将创建和getInstance()分开,单独为创建加synchronized关键字,也是可以的:
    public class SingletonTest{
    	private static SingletonTest instance=null;
    
    	private SingletonTest(){}
    
    	private static synchronized void syncInit(){
    		if(instance==null){
    			instance=new SingletonTest();
    		}
    	}
    
    	public static SingletonTest getInstance(){
    		if(instance==null){
    			syncInit();
    		}
    		return instance;
    	}
    }
    
    • 采用 “影子实例” 的方法为单例对象的属性同步更新:
    public class SingletonTest{
    	private static SingletonTest instance=null;
    	
    	private Vector properties=null;
    	
    	public Vector getProperties(){
    		return properties;
    	}
    
    	private SingletonTest(){}
    
    	private static synchronized void syncInit(){
    		if(instance==null){
    			instance=new SingletonTest();
    		}
    	}
    
    	public static SingletonTest getInstance(){
    		if(intance==null){
    			syncInit();
    		}
    		return instance;
    	}
    
    	public void updateProperties(){
    		SingletonTest shadow=new SingletonTest();
    		properties=shadow.getProperties();
    	}
    }
    
    • 单例模式的特点:
      • 单例模式理解起来简单,具体实现起来是有一定难度的\
        • 同步
        • 异步
      • synchronized关键字锁定的是对象,使用的时候要在恰当的地方使用:
        • 注意需要使用锁的对象和过程,有时候不是整个对象及整个过程都需要锁
    • 采用类的静态方法,可以实现单例模式的效果
      • 类的静态方法和单例模式的区别:
        • 静态类不能实现接口:
          • 从类的角度说,是可以的,但是这样就会破坏静态了
          • 接口中不允许有static修饰的方法,即使实现了也是非静态的
        • 单例可以被延迟启动:
          • 静态类在第一次加载时初始化
          • 单例延迟加载,是因为有些类比较庞大,延迟加载有助于提升性能
        • 单例可以被继承:
          • 单例中的方法可以被重写
          • 静态类内部方法都是static,无法重写
        • 单例比较灵活:
          • 从实现上讲,单例只是一个普通的Java类,只要满足单例的基本要求,可以随心所欲地实现其它功能
          • 静态类不行
      • 单例模式内部可以就是用一个静态类实现

    建造者模式(Builder)

    • 工厂模式提供的是创建单个类的模式
    • 建造者模式: 将各种产品集中起来进行管理,用来创建复合对象
      • 复合对象: 指某个类具有不同的属性
    • 建造者模式就是抽象工厂类模式和Test类结合起来得到的
    • 代码实现: 一个Sender接口,两个实现类MailSenderSmsSender
    - Builder
    public class Builder{
    	private List<Sender> list=new ArrayList<Sender>();
    
    	public void produceMailSender(int count){
    		for(int i=0;i<count;i++){
    			list.add(new MailSender());
    		}
    	}
    
    	public void produceSmsSender(int count){
    		for(int i=0;i<count;i++){
    			list.add(new SmsSender());
    		}
    	}
    }
    
    
    
    
    - 测试类
    public class Test{
    	public static void main(String[] args){
    		Builder builder=new Builder();
    		builder.produceMailSender(10);
    	}
    }
    
    • 建造者模式将很多功能集成到一个类里,这个类就可以创造出比较复杂的模块
    • 建造者模式和工厂模式的区别:
      • 工厂模式关注的是创建单个产品
      • 建造者模式关注的是创建符合对象,多个部分

    原型模式(Prototype)

    • 原型模式: 将一个对象作为原型,进行复制,克隆,产生一个和原对象类似的新对象
    • 原型模式虽然是创建型模式,但是与工厂模式没有关系
    • 在Java中,复制对象是通过clone() 实现的
    - 原型类
    public class Prototype implements Cloneable{
    	public Object clone() throws CloneNotSupportedException{
    		Prototype proto=(Prototype)super.clone();
    		return proto;
    	}
    }
    
    • 一个原型类,只需要实现Cloneable接口,重写clone() 方法
    • clone方法可以改写为任何名称,因为Cloneable接口是个空接口,可以任意定义实现类的方法名
    • 重点是super.clone():
      • super.clone() 方法调用的是Object的**clone() ** 方法
      • 在Object类中 ,clone() 方法时native
    • 对象的深复制和浅复制:
      • 深复制:
        • 将一个对象复制后,不论是基本类型还是引用类型,都是重新创建的
        • 深复制会进行完全彻底的复制
      • 浅复制:
        • 将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型指向的还是原对象的引用
    public class Prototype implements Cloneable,Serializable{
    	private static final long serialVersionUID=1L;
    	private String string;
    	private SerializableObject obj;
    
    	/* 浅复制 */
    	public Object clone() throws CloneNotSupportedException{
    		Prototype proto=(Prototype)super.clone();
    		return proto;
    	}
    	
    	/* 深复制 */
    	public Object clone() throws IOException,ClassNotFoundException{
    	
    	/* 写出当前对象的二进制流 */
    	ByteArrayOutputStream bos=new ByteArrayOutputStream();
    	ObjectOutputStream oos=new ObjectOutputStream(bos);
    	oos.writeObject(this);
    
    	/* 读入二进制流产生的新对象 */
    	ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
    	OnjectInputStream ois=new ObjectInputStream(bis);
    	
    	return ois.readObject();
    	}
    	
    	public String getString(){
    		return string;
    	}
    
    	public void setString(String string){
    		this.string=string;
    	}
    
    	public SerializableObject getObj(){
    		return obj;
    	}
    
    	public void setObj(SerializableObject obj){
    		this.obj=obj;
    	}
    
    }
    
    	class SerializableObject implements Serializable{
    		private static final long serialVersionUID=1L;
    	}
    
    • 要实现深复制:
      • 要采用流的形式读入当前对象的二进制输入
      • 再写出二进制数据对应的对象

    结构型模式

    适配器模式(Adapter Pattern)

    • 对象的适配器模式是各种结构型模式的起源
      在这里插入图片描述
    • 适配器模式: 将某个类的接口转换成客户端期望的另一个接口表示
    • 目的: 消除由于接口不匹配所造成的类的兼容性问题
    • 适配器模式主要分为三类:
      • 类的适配器模式
      • 对象的适配器模式
      • 接口的适配器模式
    类的适配器模式

    在这里插入图片描述

    • 核心思想: 有一个Source类,拥有一个方法待适配,目标接口是Targetable, 通过Adapter类,将Source的功能扩展到Targetable
    - Source
    public class Source{
    	public void method1(){
    		System.out.println("This is original method!");
    	}
    } 
    
    - Targetable
    public interface Targetable{
    	/* 与原类中的方法相同 */
    	public void method1();
    
    	/* 新类方法 */
    	public void method2();
    }
    
    - Adapter
    public class Adapter extends Source implemments Targetable{
    	@Override
    	public void method2(){
    		System.out.println("This is the targetable method!");
    	}
    }
    
    • Adapter类继承Source类,实现Targetable接口:
    - AdapterTest
    public class AdapterTest{
    	public static void main(String[] args){
    		Targetable target=new Adapter();
    		target.method1();
    		target.method2();
    	}
    }
    
    • 这样Targetable接口的实现类就具有Source类的功能
    对象的适配器模式
    • 基本思路和类的适配器相同,只是将Adapter类作修改 ,不继承Source类,而是持有Source类的实例,以达到解决兼容性问题
      在这里插入图片描述
    - Wrapper
    public class Wrapper implements Targetable{
    	private Source source;
    
    	public Wrapper(Source source){
    		super();
    		this.source=source;
    	}
    
    	@Override
    	public void method1(){
    		source.method1();
    	}
    
    	@override
    	public void method2(){
    		System.out.println("This is the targetable method!");
    	}
    }
    
    
    
    
    - Test
    public class AdapterTest{
    	public static void main(String[] args){
    		Source source=new Source();
    		Targetable target=new Wrapper(source);
    		target.method1();
    		target.nethod2();
    	}
    }
    
    接口的适配器模式
    • 一个接口中有多个抽象方法,当写该接口的实现类时,必须实现该接口的所有方法,这样明显比较浪费,因为并不是所有的方法都是需要用到的,有时只要引入一些即可.为了解决这样的问题,引入了接口适配器模式
    • 接口适配器模式: 借助于一个抽象类,该抽象类实现了该接口以及所有的方法,只需要和该抽象类进行联系即可.
    • 只需要写一个类,继承该抽象类,重写需要用到的方法
      在这里插入图片描述
    - Sourceable
    public interface Sourceable{
    	public void method1();
    	public void method2();
    }
    
    
    
    
    - Wrapper-抽象类
    public abstract class Wrapper implements Sourceable{
    	public void method1(){}
    
    	public void method2(){}
    }
    
    
    
    
    - SourceSub1
    public class SourceSub1 extends Wrapper{
    	public void method1(){
    		System.out.println("The sourceable interface's first Sub");
    	}
    }
    
    
    
    
    - SourceSub2
    public class SourceSub2 extends Wrapper(){
    	public void method2(){
    		System.out.println("The Sourceable interface's second Sub");
    	}
    }
    
    
    
    
    - WrapperTest
    public class WrapperTest{
    	public static void main(String[] args){
    		Sourceable source1=new SourceSub1();
    		Sourceable source2=new SourceSub2();
    
    		source1.method1();
    		source1.method2();
    		source2.method1();
    		source2.method2();
    	}
    }
    
    • 三种适配器模式的应用场景:
      • 类的适配器模式:
        • 当希望一个类转换成满足另一个新接口的类时,可以使用类的适配器模式
        • 创建一个新类,继承原有的类,实现新的接口即可
      • 对象的适配器模式:
        • 当希望一个对象转换成满足另一个新接口的对象时,可以使用对象的适配器模式
        • 创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法即可
      • 接口的适配器模式:
        • 当不希望实现一个接口中所有的方法时,可以使用接口的适配器模式
        • 创建一个抽象类Wrapper,实现所有方法,写其它类时,只要继承抽象类即可

    装饰器模式(Decorator)

    • 装饰器模式: 给一个对象动态地增加一些新的功能
    • 装饰器模式要求装饰对象和被装饰对象实现同一个接口, 装饰对象持有被装饰对象的实例
      在这里插入图片描述
    • Source类时被装饰类 ,Decorator类是装饰类,可以为Source类动态地增加一些功能:
    - Sourceable
    public interface Sourceable{
    	public void method();
    }
    
    
    
    
    - Source
    public class Source implements Sourceable{
    	@Override
    	public void method(){
    		System.out.println("The original method!");
    	}
    }
    
    
    
    
    - Decorator
    public class Decorator implements Sourceable{
    	private Sourceable source;
    	public Decorator(Sourceable source){
    		super();
    		this.source=source;
    	}
    
    	@Override
    	public void method(){
    		System.out.println("Before decorator!");
    		source.method();
    		System.out.println("After decorator!");
    	}
    }
    
    
    
    
    -Test
    public class DecoratorTest{
    	public static void main(String[] args){
    		Sourceable source=new Source();
    		Sourceable obj=new Decorator(source);
    		obj.method();
    	}
    }
    
    • 装饰器模式应用场景:
      • 需要扩展一个类的功能
      • 动态地为一个对象增加功能,而且还能动态地撤销(继承的功能是静态的,不能动态增删)
    • 装饰器模式的缺点: 产生过多类似的对象,不易排错

    代理模式(Proxy)

    • 代理模式: 创建一个代理类,替原对象进行一些操作
      在这里插入图片描述
    - Sourceable
    public interface Sourceable{
    	public void method();
    }
    
    
    
    
    - Source
    public class Source implements Sourceable{
    	@Override
    	public void method(){
    		System.out.println("The original method!");
    	}
    }
    
    
    
    
    - Proxy
    public class Proxy implements Sourceable{
    	private Source source;
    	public Proxy(){
    		super();
    		this.source=new Source;
    	}
    
    	@Override
    	public void method(){
    		before();
    		source.method();
    		after();
    	}
    
    	public void before(){
    		System.out.println("Before Proxy!");	
    	}
    	
    	public void after(){
    		System.out.println("After Proxy!");
    	}	
    }
    
    
    
    
    - ProxyTest
    public class ProxyTest{
    	public static void main(String[] args){
    		Sourceable source=new Proxy();
    		source.method();
    	}
    }
    
    • 代理模式的应用场景:
      • 已有的方法在使用的时候需要对原有的方法进行改进,有两种方法:
        • 修改原有的方法来适应: 这样违反了"对扩展开放,对修改关闭"的原则 .不推荐使用
        • 采用一个代理类调用原有的方法,且对产生的结果进行控制. 即代理模式
    • 使用代理模式,可以将功能划分的更加清晰,有助于后期维护

    外观模式(Facade)

    • 在Spring中,可以将类与类之间的关系配置到配置文件中
    • 外观模式: 为了解决类与类之间的依赖关系,将类鱼雷之间的关系放到一个Facade类中,降低类与类之间的耦合度,该模式中没有涉及到接口
      在这里插入图片描述
    - CPU
    public class CPU{
    	public void startup(){
    		System.out.println("CPU startup!");
    	}
    
    	public void shutdown(){
    		System.out.println("CPU shutdown!");
    	}
    }
    
    
    
    
    - Memory
    public class Memory{
    	public void startup(){
    		System.out.println("Memory startup!");
    	}
    
    	public void shutdown(){
    		System.out.println("Memory shutdown!");
    	}
    }
    
    
    
    
    - Disk
    public class Disk{
    	public void startup(){
    		System.out.println("Disk startup!");
    	}
    
    	public void shutdown(){
    		System.out.println("Disk shutdown!");
    	}
    }
    
    
    
    
    - Computer
    public class Computer{
    	private CPU cpu;
    	private Memory memory;
    	private Disk disk;
    
    	public Computer(){
    		cpu=new CPU();
    		memory=new Memory();
    		disk=new Disk();
    	}
    
    	public void startup(){
    		System.out.println("Start the computer!");
    		cpu.startup();
    		memory.startup();
    		disk.startup();
    		System.out.println("Start the computer finished!");
    	}
    
    	public void shutdown(){
    		System.out.println("Begin to close the computer!");
    		cpu.shutdown();
    		memory.shutdown();
    		disk.shutdown();
    		System.out.println("Computer closed!");
    	}
    }
    
    
    
    
    -User
    public class User{
    	public static void main(String[] args){
    		Computer computer=new Computer();
    		computer.startup();
    		computer.shutdown();
    	}
    }
    
    • 如果没有Computer,CPU,Memory,Disk之间会互相持有实例,产生关系,这样会造成严重依赖
    • 修改一个类,可能会带来其它类的修改
    • 有了Computer类,各个类之间的关系就放在类Computer类里,这样就起到解耦的作用

    桥接模式(Bridge)

    • 桥接模式: 将事物和具体实现分开,二者可以各自独立的变化
    • 将抽象化与实现化解耦,使得二者可以独立变化:
      • JDBC桥DriverManager:
        • JDBC连接数据库的时候,在各个数据库之间进行切换,基本不需要改动太多的代码,甚至一点不用改动
        • 原因在于JDBC提供统一接口,每个数据库提供各自实现,用一个叫作数据库驱动的程序来桥接即可
          在这里插入图片描述
    - Sourceable
    public interface Sourceable{
    	public void method();
    }
    
    
    
    
    - SourceSub1
    public class SourceSub1 implements Sourceable{
    	@Override
    	public void method(){
    		System.out.println("This is the first sub!");
    	}
    }
    
    
    
    
    - SourceSub2
    public class SourceSub2 implements Sourceable{
    	@Override
    	public void method(){
    		System.out.println("This is the second sub!");
    	}
    }
    
    
    
    
    - 定义一个桥,持有Sourceable的一个实例
    public abstract class Bridge{
    	private Sourceable source;
    
    	public void method(){
    		source.method();
    	}
    
    	public Sourceable getSource(){
    		return source;
    	}
    
    	public void getSource(Sourceable source){
    		this.source=source;
    	}
    }
    
    
    
    
    - MyBridge
    public class MyBridge extends Bridge{
    	public void method(){
    		getSource().method();
    	}
    }
    
    
    
    
    - BridgeTest
    public class BridgeTest{
    	public static void main(String[] args){
    		Bridge bridge=new MyBridge();
    
    		/* 调用第一个对象 */
    		Sourceable source1=new SourceSub1();
    		bridge.setSource(source1);
    		bridge.method();
    
    		/* 调用第二个对象 */
    		Sourceable source2=new SourceSub2();
    		bridge.setSource(source2);
    		bridge.method();
    	}
    }
    
    • 通过对Bridge类的调用,实现了对接口Sourceable的实现类SourceSub1和SourceSub2的调用
    • 示例: JDBC连接原理
      在这里插入图片描述

    组合模式(Composite)

    • 组合模式: 部分-整体模式,在处理类似树形结构的问题时比较方便
      在这里插入图片描述
    - TreeNode
    public class TreeNode{
    	private String name;
    	private TreeNode parent;
    	private Vector<TreeNode> children=new Vector<TreeNode>();
    
    	public TreeNode(String name){
    		this.name=name;
    	}
    
    	public String getName(){
    		return name;
    	}
    
    	public void setName(String name){
    		this.name=name;
    	}
    
    	public TreeNode getParent(){
    		return parent;
    	}
    
    	public void setParent(TreeNode parent){
    		this.parent=parent;
    	}
    
    	/* 添加孩子节点 */
    	public void add(TreeNode node){
    		children.add(node);
    	}
    
    	/* 删除孩子节点 */
    	public void remove(TreeNode node){
    		children.remove(node);
    	}
    
    	/* 获得孩子节点 */
    	public Enumeration<TreeNode> getChildren(){
    		return children.elements();
    	}
    }
    
    
    
    
    - Tree
    public class Tree{
    	TreeNode root=null;
    
    	public Tree(String name){
    		root=new TreeNode(name);
    	}
    
    	public void main(String[] args){
    		Tree tree=new Tree("A");
    		TreeNode nodeB=new TreeNode("B");
    		TreeNode nodeC=new TreeNode("C");
    
    		nodeB.add(nodeC);
    		tree.root.add(nodeB);
    		System.out.println("Build the tree finished!");
    	}
    }
    
    • 组合模式使用场景:
      • 将多个对象组合在一起进行操作
      • 常用于表示树形结构中:二叉树

    享元模式

    • 享元模式: 主要目的是实现对象共享,即共享池
    • 当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用
      在这里插入图片描述
    • FlyWeightFactory: 负责创建和管理享元单元
      • 当一个客户端请求时,工厂需要检查当前对象池中是否有符合条件的对象
      • 如果有,就返回已经存在的对象
      • 如果没有,就创建一个新对象
    • FlyWeight: 超类
    • 共享的对象的特点:
      • 共享对象有一些共同的属性
      • 这些属性对于每个连接来说都是一样的
    • 基于共享对象的特点,可以用享元模式处理共享对象:
      • 将类似属性作为内部数据
      • 其它的属性作为外部数据
      • 在方法调用时,当作参数传进来
    • 这样可以节省内存空间,减少实例的数量
    • 示例: 数据库连接池
      在这里插入图片描述
    public class ConnectionPool{
       private Vector<Connection> pool;
    
       /* 公有属性 */
       private String url="jdbc:mysql://localhost:3306/test";
       private String username="root";
       private String password="root";
       private String driverClassName="com.mysql.jdbc.Driver";
       private int poolSize=100;
       private static ConnectionPool instance=null;
       Connection conn=null;
    
       /* 构造方法,负责初始化 */
       private ConnectionPool(){
       	pool = new Vector<Connection>(poolSize);
       	
       	for(int i=0;i<poolSize;i++){
       		try{
       			Class.forName(driverClassName);
       			conn=DriverManager.getConnection(url,user,password);
       			pool.add(conn);
       	}catch(ClassNotFoundException e){
       			e.printStackTrace();
       	}catch(SQLEXception e){
       			e.printStackTrace();
       	}
       }	
    }
    
       /* 返回连接到连接池 */
       public sysnchronized void release(){
       		pool.add(conn);
       }
    
       /* 返回连接池中的一个数据库 */
       public syschronized Connection getConnection(){
       		if(pool.size()>0){
       			Connection conn=pool.get(0);
       			pool.remove(conn);
       			return conn;
       		}else{
       			return null;
       		}
       }
    }
    
    • 通过连接池的连接,实现数据库连接的共享:
      • 不需要每一次重新创建连接,节省数据库重新创建的开销,提升了系统系能

    行为型模式

    • 11种行为模式的关系:
      • 第一类: 通过父类与子类的关系进行实现
      • 第二类: 通过两个类之间的关系进行实现
      • 第三类: 通过类的状态进行实现
      • 第四类: 通过中间类进行实现
        -

    策略模式(Strategy)

    • 策略模式:
      • 定义了一系列算法,并将每个算法封装起来,可以相互替换,算法的变化不会影响到使用算法的用户
      • 设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口
      • 设计一个抽象类(选用,作为辅助类),提供辅助函数
        在这里插入图片描述
    • ICalculator接口提供统一的方法
    • AbstractCalculator是抽象辅助类,提供辅助方法
    - ICalculator
    public interface ICalculator{
    	public int calculate(String exp);
    }
    
    
    
    
    - AbstractCalculator
    public abstract class AbstractCalcuator{
    	public int[] split(String exp,String opt){
    		String array[]=exp.split(opt);
    		int arrayInt[]=new int[2];
    		arrayInt[0]=Integer.parseInt(array[0]);
    		arrayInt[1]=Integer.parseInt(array[1]);
    
    		return arrayInt;
    	}
    } 
    
    
    
    
    - Plus
    public class Plus extends AbstractCalculator implements ICalculator{
    	@Override
    	public int calculate(String exp){
    		int arrayInt[]=split(exp,"\\+");
    		return arrayInt[0]+arrayInt[1];
    	}
    }
    
    
    
    - Minus
    public class Minus extends AbstractCalculator implements ICalculator{
    	@Override
    	public int calculate(String exp){
    		int arrayInt[]=split(exp,"-");
    		return arrayInt[0]-arrayInt[1];
    	}
    	
    }
    
    
    
    
    - Multiply
    public class Multiply extends AbstractCalculator implements ICalculator{
    	@Override
    	public int calculate(String exp){
    		int arrayInt[]=split(exp,"\\*");
    		return arrayInt[0]*arrayInt[1];
    	}
    }
    
    
    
    
    - StrategyTest
    public class StrategyTest{
    	public static void mian(String[] args){
    		String exp="2+8";
    		ICalculator cal=new Plus();
    		int result=cal.calculate(exp);
    		System.out.println(result);
    	}
    }
    
    • 策略模式的决定权在于用户:
      • 系统本身提供不同算法的实现
      • 新增或删除算法
      • 对各种算法做封装
    • 策略模式多用在算法决策系统中,外部用户只需要决定使用哪一个算法即可

    模板方法模式(Template Method)

    • 模板方法模式:
      • 一个抽象类中,定义一个主方法
      • 再定义无数个方法,可以是抽象的,也可以是实际的方法
      • 定义一个子类,继承抽象类,重写抽象类中的方法
      • 通过调用抽象类,实现对子类的调用
        -
      • AbstractCalculator类中定义一个主方法calculate()
      • calculate() 调用split()
      • PlusMinus分别继承AbstractCalculator
      • 通过对AbstractCalculator的调用实现对子类的调用
    public abstract class AbstractCalculator{
    	/* 主方法,实现对本类的其它方法的调用 */
    	public final int calculate(String exp,String opt){
    		int array[]=split(exp,opt)
    		return calculate(array[0],array[1]);
    	}
    
    	/* 抽象方法,需要子类进行重写 */
    	abstract public int calculate(int num1,int num2);
    	
    	public int[] split(String exp,String opt){
    			String array[]=exp.split(opt);
    			int arrayInt[]=new int[2];
    			arrayInt[0]=Integer.parseInt(array[0]);
    			arrayInt[1]=Integer.parseInt(array[1]);
    			return arrayInt;
    	}
    }
    
    
    
    
    - Plus
    public class Plus extends AbstractCalculator{
    	@Override
    	public int calculate(int num1,int num2){
    		return num1+num2;
    	}
    }
    
    
    
    
    - StrategyTest
    public class StrategyTest{
    	public static void main(String[] args){
    		String exp="8+8";
    		AbstractCalculator cal=new Plus();
    		int result=cal.calculate(exp,"\\+");
    		System.out.println(result);
    	}
    }
    

    Test的执行过程:

    • 首先将exp和"\ \ +"做参数,调用AbstractCalculator类里的**calculate(String,String)**方法
    • calculate(String,String) 里调用同类的split()
    • 然后再调用calculate(int,int) 方法
    • 从这个方法进入到子类中
    • 执行完return num1+num2之后,将值返回到AbstractCalculator类,赋值给result, 打印出来

    观察者模式(Observer)

    • 观察者模式是类与类之间的关系,不涉及继承
    • 观察者模式类似邮件订阅和RSS订阅:
      • 当你订阅了该内容,如果后续有更新,会及时接收到通知
    • 观察者模式: 当一个对象变化时,依赖该对象的对象都会接收到通知,并且随着变化.对象之间是一对多的关系
      在这里插入图片描述
    • MySubject类是主对象
    • Observer1Observer2是依赖于MySubject的对象
    • MySubject变化时 ,Observer1Observer2必然变化
    • AbstractSubject类中定义者需要监控的对象列表,可以对这些对象进行修改:增加或者删除被监控对象
    • MySubject变化时 ,AbstractSubject类负责通知在列表内存在的对象
    - Observer
    public interface Observer{
    	public void update();
    }
    
    
    
    
    - Observer1
    public class Observer1 implements Observer{
    	@Override
    	public void update(){
    		System.out.println("Observer1 has received!");
    	}
    }
    
    
    
    
    - Observer2
    public class Observer2 implements Observer{
    	@Override
    	public void update(){
    		System.out.println("Observer2 has received!");
    	}
    }
    
    
    
    
    - Subject
    public interface Subject{
    	/* 增加观察者 */
    	public void add(Observer observer);
    
    	/* 删除观察者 */
    	public void del(Observer observer);
    
    	/* 通知所有观察者 */
    	public void notifyObservers();
    
    	/* 自身的操作 */
    	public void operation();
    }
    
    
    
    
    - AbstractSubject
    public abstract class AbstractSubject implements Subject{
    	private Vector<Observer> vector=new Vector<Observer>();
    	
    	@Override
    	public void add(Observer observer){
    		vector.add(observer);
    	} 
    	
    	@Override
    	public void del(Observer observer){
    		vector.remove(observer);
    	}
    
    	@Override
    	public void notifyObservers(){
    		Enumeration<Observer> enumo=vector.elements();
    		while(enumo.hasMoreElements()){
    			enumo.nextElement().update();
    		}
    	}
    }
    
    
    
    
    - MySubject
    public class MySubject extends AbstractSubject{
    	@Override
    	public void operation(){
    		System.out.println("update self!");
    		notifyObservers();
    	}
    }
    
    
    
    
    - ObserverTest
    public class ObserverTest{
    	public static void main(String[] args){
    		Subject sub=new MySubject();
    		sub.add(new Observer1());
    		sub.add(new Observer2());
    
    		sub.operation();
    	}
    }
    
    • 观察者模式根据关系图,新建项目,使用代码按照总体思路走一遍,这样容易理解观察者模式的思想

    迭代子模式(Iterator)

    • 迭代子模式是类与类之间的关系,不涉及继承
    • 迭代子模式: 顺序访问聚集中的对象. 包含两层意思:
      • 聚集对象: 需要遍历的对象
      • 迭代器对象: 用于对聚集对象进行遍历访问
        在这里插入图片描述
    • MyCollection中定义了集合的一些操作
    • MyIterator中定义了一系列迭代操作,并且持有Collection实例
    - Collection
    public interface Collection{
    	public Iterator iterator();
    
    	/* 取得集合元素 */
    	public Object get(int i);
    
    	/* 取得集合大小 */
    	public int size();
    }
    
    
    
    
    - Iterator
    public interface Iterator{
    	// 前移
    	puublic Object previous();
    
    	// 后移
    	public Object next();
    	public boolean hasNext();
    
    	// 取得第一个元素
    	public Object first(); 
    }
    
    
    
    
    - MyCollection
    public class MyCollection implements Collection{
    	public String string[]={"A","B","C","D","E"};
    
    	@Override
    	public Iterator iterator(){
    		return new MyIterator(this);
    	}
    
    	@Override
    	public Object get(int i){
    		return string[i];
    	}
    
    	@Override
    	public int size(){
    		return string.length;
    	}
    }
    
    
    
    
    - MyIterator
    public class MyIterator implements Iterator{
    	private Collection collection;
    	private int pos=-1;
    
    	public MyIterator(Collection collection){
    		this.collection=collection;
    	}
    
    	@Override
    	pbulic Object previous(){
    		if(pos>0){
    			pos--;
    		}
    		return collection.get(pos);
    	}
    
    	@Override
    	public Object next(){
    		if(pos<collection.size()-1){
    			pos++;
    		}
    		return collection.get(pos);
    	}
    
    	@Override
    	public Object hasNext(){
    		if(pos<collection.size()-1){
    			return true;
    		}else{
    			return false;
    		}
    	}
    
    	@Override
    	public Object first(){
    		pos=0;
    		return collection.get(pos);
    	}
    
    
    }
    
    
    
    
    - Test
    public class Test{
    	Collection collection=new MyCollection();
    	Iterator it=collection.iterator();
    
    	whhile(it.hasNext()){
    		System.out.println(it.next());
    	}
    }
    
    • JDK中各个类都是这些基本的集合,加上一些设计模式,再加一些优化组合到一起的,只要掌握这些,可以写出自定义的集合类,甚至框架

    责任链模式(Chain of Responsibility)

    • 类与类之间的关系,不涉及继承
    • 责任链模式:
      • 有多个对象,每个对象持有对下一个对象的引用,这样形成一条链,直到某个对象决定处理该请求
      • 请求发出者并不清楚到底最终哪个对象会处理该请求
    • 责任链模式可以实现 :在隐瞒客户端的情况下,对系统进行动态调整
      在这里插入图片描述
    • Abstracthandler类提供了getset方法,方便MyHandler类设置和修改引用对象
    • MyHandler类是核心,实例化后生成一系列相互持有的对象,构成一条链
    - Handler
    public interface Handler{
    	public void operator();
    }
    
    
    
    
    - AbstractHandler
    public abstract class AbstractHandler{
    
    	private Handler handler;
    
    	private Handler getHandler(){
    		return handler;
    	}
    
    	private void setHandler(Handler handler){
    		this.handler=handler;
    	}
    }
    
    
    
    
    - MyHandler
    public class MyHandler extends AbstractHandler implements Handler{
    	private String name;
    	
    	public MyHandler(String name){
    		this.name=name;
    	}
    
    	@Override
    	public void operator(){
    		System.out.println(name+"deal!");
    		if(getHandler()!=null){
    			getHandler().operator();
    		}
    	}
    } 
    
    
    
    
    - Test
    public class Test{
    	public static void main(String[] args){
    		MyHandler h1=new MyHandler("h1");
    		MyHanlder h2=new MyHandler("h2");
    		MyHandler h3=new MyHandler("h3");
    		
    		h1.setHandler(h2);
    		h2.setHandler(h3);
    
    		h1.operator();
    	}
    }
    
    • 链接上的请求可以是一条链,可以是一个树,还可以是一个环
    • 模式本身不受这个约束,需要自定义实现
    • 在同一个时刻,命令只允许由一个对象传给另一个对象,不允许传给多个对象

    命令模式(Command)

    • 类与类之间的关系,不涉及继承
    • 命令模式理解示例:
      • 司令员的作用是: 发出口令
      • 口令经过传递,传到士兵耳中,士兵去执行
      • 这个过程好在:司令,口令,士兵三者相互解藕
      • 任何一方都不用去依赖其它方,只需要做好自身的事即可
      • 司令员要的是结果,不会去关注士兵到底怎么实现的
        -
    • Invoker是调用者(司令员)
    • Receiver是被调用者(士兵)
    • MyCommand是命令,实现了Command接口,持有接收对象
    - Command
    public interface Command{
    	public void exe();
    }
    
    
    
    
    - MyCommand
    public class MyCommand implements Command{
    	private Receiver receiver;
    
    	public MyCommand(Receiver receiver){
    		this.receiver=receiver;
    	}
    
    	@Override
    	public void exe(){
    		receiver.action();
    	}
    } 
    
    
    
    
    - Receiver
    public class Receiver{
    	public void action(){
    		System.out.println("Command Received!");
    	}
    }
    
    
    
    
    - Invoker
    public class Invoker{
    	private Command command;
    
    	public Invoker(Command command){
    		this.command=command;
    	}
    
    	public void action(){
    		command.exe();
    	}
    }
    
    
    
    
    - Test
    public class Test{
    	public static void main(String[] args){
    		Receiver receiver=new Receiver();
    		Command cmd=new MyCommand(receiver);
    		Invoker Invoker=new Invoker(cmd);
    		invoker.action();
    	}
    }
    
    • 命令模式的目的: 达到命令的发出者和执行者之间的解耦,实现请求和执行分开
    • Struts其实就是一种将请求和呈现分离的技术,使用了命令模式的设计思想

    备忘录模式(Memento)

    • 备忘录模式 :主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象
    • 备忘录模式理解:
      • 假设有原始类A,A中有各种属性,A可以决定需要备份的属性
      • 备忘录类B用来存储A的一些内部状态
      • 类C用来存储备忘录,并且只能存储,不能进行修改等操作
        在这里插入图片描述
    • Original类是原始类,里面有需要保存的属性value及创建一个备忘录类,用来保存value
    • Memento类是备忘录类
    • Storage类是存储备忘录的类,持有Memento类的实例
    - Original
    public class Original{
    	private String value;
    
    	private String getValue(){
    		return value;
    	}
    
    	private void setValue(String value){
    		this.value=value;
    	}
    
    	public Original(String value){
    		this.value=value;
    	}
    
    	public Memento createMemento(){
    		return new Memento(value);
    	}
    
    	public void restoreMemento(Memento memento){
    		this.value=memento.getValue();
    	}
    }
    
    
    
    
    - Memento
    public class Memento{
    	private String value;
    
    	public Memento(String value){
    		this.value=value;
    	}
    
    	public String getValue(){
    		return value;
    	}
    
    	public void setValue(String value){
    		this.value=value;
    	}
    }
    
    
    
    
    - Storage
    public class Storage{
    	private Memento memento;
    
    	public Storage(Memento memento){
    		this.memento=memento;
    	}
    
    	public Memento getMemento(){
    		return memento;
    	}
    
    	public void setMemento(Memento memento){
    		this.memento=memento;
    	}
    }
    
    
    
    
    - Test
    public class Test{
    	public static void main(String[] args){
    		// 创建原始类
    		Original original=new Original("egg");
    
    		// 创建备忘录
    		Storage storage=new Storage(original.createMemento());
    
    		// 修改原始类的状态
    		System.out.println("初始状态为:"+original.getValue());
    		original.setValue("bulk");
    		System.out.println("修改后的状态:"+original.getValue());
    
    		// 恢复原始类的状态
    		original.restoreMemento(storage.getMemento());
    		System.out.println("恢复后的状态为:"+original.getValue());
    	}
    }
    
    • 新建原始类时 ,value被初始化为egg, 后经过修改,将value值修改为bulk, 最后进行恢复状态,结果成功恢复

    状态模式(State)

    • 状态模式 :当对象的状态改变时,同时改变对象的行为
    • 状态模式理解示例:
      • QQ有几种不同的状态:在线,隐身,忙碌等
      • 每个状态对应不同的操作,而且好友也能看到相关的状态
    • 状态模式包括两层含义:
      • 可以通过改变状态来获得不同的行为
      • 对象状态的变化可以被发现
        -
    • State类是个状态类
    • Context类可以实现切换
    - State
    public class State{
    	private String value;
    
    	private String getValue(){
    		return value;
    	}
    
    	private void setValue(String value){
    		this.value=value;
    	}
    
    	public void method1(){
    		System.out.println("Execute the first opt!");
    	}
    
    	public void method2(){
    		System.out.println("Execute the second opt!");
    	}
    }
    
    
    
    
    - Context
    public class Context{
    	private State state;
    
    	private Context(State state){
    		this.state=state;
    	}
    
    	public State getState(){
    		return state;
    	}
    
    	public void setState(){
    		this.state=state;
    	}
    
    	public void method(){
    		if(state.getValue().equals("state1")){
    			state.method1();
    		}else if(state.getValue().equals("state2")){
    			state.method2();
    		}
    	}
    }
    
    
    
    
    - Test
    public class Test{
    	public static void main(String[] args){
    		State state=new State();
    		Context context=new Context(state);
    
    		// 设置第一种状态
    		state.setValue("state1");
    		context.method();
    
    		// 设置第二种状态
    		state.setValue("state2");
    		context.method();
    	}
    }
    
    • 状态模式的应用场景十分广泛:在做网站的时候,希望根据对象的属性,区别一些功能等,比如说权限控制等等

    访问者模式(Visitor)

    • 访问者模式将数据结构和作用于结构上的操作解耦,使得操作集合可以相对自由地进行演化
    • 访问者模式适用于数据结构相对稳定,算法容易变化的系统:
      • 访问者模式使得算法操作增加变得更加容易
    • 若系统数据结构对象易于变化,经常有新的对象增加进来,则不适合使用访问者模式
    • 访问者模式的特点:
      • 优点: 增加操作容易
        • 增加操作意味着增加新的访问者
        • 访问者模式将有关行为集中到一个访问者对象中, 这些行为的改变不影响系统数据结构
      • 缺点: 增加新的数据结构很困难
    • 访问者模式 :是一种分离对象数据结构和行为的方法,通过这种分离,可以达到为一个被访问者动态添加新的操作而无需做任何修改的效果
      -
    • 一个Visitor类,存放要访问的对象
    • Subject类中有accept方法,接收将要访问的对象 ,getSubject() 获取将要被访问的属性
    - Visitor
    public interface Visitor{
    	public void visit(Subject sub);
    }
    
    
    
    
    - MyVisitor
    public class MyVisitor implements Visitor{
    	@Override
    	public void visit(Subject sub){
    		System.out.println("visit the subject:"+sub.getSubject());
    	}
    }
    
    
    
    
    - Subject
    public interface Subject{
    	public void accept(Visitor visitor);
    	public String getSubject();
    }
    
    
    
    
    - MySubject
    public class MySubject implements Subject{
    	@Override
    	public void accept(Visitor visitor){
    		visitor.visit(this);
    	}
    	@Override
    	public String getSubject(){
    		return "love";
    	}
    }
    
    
    
    
    - Test
    public class Test{
    	public static void main(String[] args){
    		Visitor visitor=new MyVisitor();
    		Subject sub=new MySubject();
    		sub.accept(visitor);
    	}
    }
    
    • 访客模式适用场景:
      • 如果要为一个现有的类增加新功能:
        • 新功能是否会与现有功能出现兼容性问题
        • 以后会不会还有新功能需要添加
        • 如果类不允许修改代码怎么处理
      • 这些问题最好的解决办法就是访客模式
      • 访问者模式适用于数据结构相对稳定的系统,将数据结构和算法解耦

    中介者模式(Mediator)

    • 中介者模式是用来降低类与类之间的耦合的:
      • 类与类之间有依赖关系的话,不利于功能的拓展和维护
      • 因为只要修改一个对象,其它关联的对象都要进行修改
    • 中介者模式: 只需要关心Mediator类的关系,具体类与类之间的关系及调度交给Mediator, 与Spring容器的作用类似
      -
    • User类统一接口
    • User1User2分别是不同的对象:
      • 二者之间有关联
      • 如果不采用中介者模式.则需要二者相互持有引用,这样二者的耦合度很高
      • 为了解耦,引入了Mediator类,提供统一接口
    • MyMediator为实现类:
      • 持有User1User2的实例,用来实现对User1User2的控制
      • 这样User1User2两个对象就可以相互独立,只需保持与Mediator之间的关系就可以
    • Mediator类用来维护
    - Mediator
    public interface Mediator{
    	public void createMediator();
    
    	public void workAll();
    }
    
    
    
    
    - MyMediator
    public class MyMediator implements Mediator{
    	private User user1;
    	private User user2;
    
    	public User getUser1(){
    		return user1;
    	}
    
    	public User getUser2(){
    		return user2;
    	}
    
    	@Override
    	public void createMediator(){
    		user1=new User1(this);
    		user2=new User2(this);
    	}
    
    	@Override
    	public void workAll(){
    		user1.work();
    		user2.work();
    	}
    }
    
    
    
    
    - User
    public abstract class User{
    	private Mediator mediator;
    	
    	public Mediator getMediator(){
    		return mediator;
    	}
    
    	public User(Mediator mediator){
    		this.mediator=mediator;
    	}
    
    	public abstract void work();
    }
    
    
    
    
    - User1
    public class User1 extends User{
    	public User1(Mediator mediator){
    		super(mediator);
    	}
    
    	@Override
    	public void work(){
    		System.out.println("user1 exe!");
    	}
    }
    
    
    
    
    - User2
    public User2 extends User{
    	public User2(Mediator mediator){
    		super(mediator);
    	}
    
    	@Override
    	public void work(){
    		System.out.println("user2 exe!");
    	}
    }
    
    
    
    
    - Test
    public class Test{
    	public static void main(String[] args){
    		Mediator mediator=new MyMediator();
    
    		mediator.createMediator();
    		mediator.workAll();
    	}
    }
    

    解释器模式(Interpreter)

    • 解释器模式一般主要应用在OOP开发中的编译器开发中,适用面比较窄
      在这里插入图片描述
    • Context类是一个上下文环境类
    • PlusMinus分别是计算的实现
    - Expression
    public interface Expression{
    	public int interpret(Context context);
    }
    
    
    
    
    - Plus
    public class Plus implements Expression{
    	@Override
    	public int interpret(Context context){
    		return context.getNum1()+context.getNum2();
    	}
    }
    
    
    
    
    - Minus
    public class Minus implements Expression{
    	@Override
    	public void interpret(Context context){
    		return context.getNum1()-context.getNum2();
    	}
    }
    
    
    
    
    - Context
    public class Context{
    	private int num1;
    	private int num2;
    
    	public Context(int num1,int num2){
    		this.num1=num1;
    		this.num2=num2;
    	}
    
    	public int getNum1(){
    		return num1;
    	}
    
    	public void setNum1(int num1){
    		this.num1=num1;
    	}
    
    	public int getNum2(){
    		return num2;
    	}
    
    	public void setNum2(int num2){
    		this.num2=num2;
    	}
    }
    
    
    
    
    - Test
    public class Test{
    	public static void main(String[] args){
    		// 计算 9+2-8
    		int result=new Minus().interpret((new Context(new Plus().interpret(new Context(9,2)),8)));
    		System.out.println(result);
    	}
    }
    
    • 解释器模式是来用作各种各样的解释器











    萌新小号主在线求关注同名公众号!分享技术干货,面试题和攻城狮故事。
    您的关注支持是我持续进步的最大动力!一起学习,共同进步。
    在这里插入图片描述

    展开全文
  • java 23 种设计模式-00-序章 java 23 种设计模式-01-工厂模式(factory) java 23 种设计模式-02-抽象工厂模式(abstract factory) 目录 系列导航索引 目录 设计模式 写在前面 创作缘由 谁适合阅读本系列教程 ...
  • 设计模式整理Java实现(源代码

    千次阅读 2016-08-31 09:55:48
    通过查询资料,整理了23种设计模式Java实现,并将各种设计模式的思想及与其他设计模式的比较,适用范围以注释的形式记录在类实现中。目前整理的设计模式有: 1.创建型模式设计模式名称设计模式名称设计模式名称...
  • Java之——23种设计模式汇总

    千次阅读 2020-02-14 19:47:13
    对于Java语言来说,通常包含有6大设计原则和23种设计模式,这些都是前辈们对于开发思想的结晶。我们学习和理解这些设计原则和设计模式,深入掌握其实现原理和使用场景,能够更好的设计我们的系统架构。编写出具有高...
  • java 23种设计模式详解

    万次阅读 多人点赞 2016-07-01 14:45:14
    设计模式的分类总体来说设计模式分为三大类:创建型模式,共五:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。结构型模式,共七:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合...
  • Java开发中的23种设计模式详解及代码和图解

    千次阅读 多人点赞 2016-08-24 15:24:01
    设计模式(Design Patterns)  ——可复用面向对象软件的基础 ...使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真
  • Java设计模式——23模式

    万次阅读 2017-05-24 22:18:11
    背景最近在整合Java设计模式,平常偶尔也遇到过,同事之间也讨论过这模式的特点,本次结合当前个人经验及网上各位大神的分享,然后得出比较通俗易懂,当然在现实的项目中,里面包含的一些设计模式是比这复杂,望读者...
  • Java设计模式

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

    千次阅读 2016-12-23 09:22:00
    java设计模式
  • 23种设计模式模式详解 Java UML类图小知识(一)设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。 使用设计模式的好处:代码的可重用性、可扩展性,可阅读性,...
  • 23种设计模式介绍以及在Java中的实现

    万次阅读 多人点赞 2016-04-24 01:06:53
    文本详细总结了23种设计模式以及他们如何应用到java中,并提供了大量的示例代码。 文章中的示例源码在github上:https://github.com/anxpp/JavaDesignPattern。 如果本文对您有所帮助,请帮忙点个赞扩散一下,谢谢!
  • java23种设计模式—工厂模式

    千次阅读 2018-06-10 22:31:59
    设计模式分为三大类: 创建型模式,共五:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 ...
  • Java设计模式设计模式学习引导

    千次阅读 多人点赞 2019-10-06 11:29:21
    截止目前,唯一放出来的只有 【Java设计模式】软件设计七大原则,阅读量两万多,看来大家都热衷于将代码写得更加优质,有水平呀~ 这篇文章主要起到小地图的作用,不涉及具体的设计模式的探讨以及设计模式的发展历程...
  • 23种设计模式java实现

    千次阅读 2016-05-27 14:02:07
    一、设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七:适配器模式、装饰器模式、代理模式、外观模式...
  • 代理模式(java设计模式

    万次阅读 2019-01-24 10:40:29
    代理模式包含如下角色: ISubject:抽象主题角色,是一个接口。该接口是对象和它的代理共用的接口。 RealSubject:真实主题角色,是实现抽象主题接口的类。 Proxy:代理角色,内部含有对真实对象RealSubject的...
  • 最经典的java 23种设计模式及具体例子

    万次阅读 多人点赞 2016-07-10 09:43:50
    最经典的java 23种设计模式及具体例子
  • 简单玩转23种Java设计模式

    千次阅读 2019-01-02 15:18:46
    什么是设计模式 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发...使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码...
  • Java23种设计模式之原型模式的学习

    千次阅读 2020-09-15 00:25:08
    这里有我整理好的Java23种设计模式的源码以及博客教程,博客教程中介绍了Java23设计的模式的各种实现方式以及应用场景,非常适用于学习以及提高我们的设计思维,如果对大家有所帮助,请记得star一下给予作者一定的...
  • Java开发中的23种设计模式详解

    千次阅读 2016-08-31 22:59:38
    设计模式(Design Patterns)  ——可复用面向对象软件的基础 ...使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真
  • 走穿java23种设计模式-5原型模式

    千次阅读 热门讨论 2017-10-07 07:28:09
    走穿java23种设计模式-5原型模式原型模式很多人对这个设计模式也是不熟悉的。因为用得也是不多,原型模式一般用于多次创建一个类的对象,获取多个这个类的对象,并进行相应的操作,一般做法是多次new出来,但是原型...
  • 设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用、多数人... 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件
  • 23 种设计模式详解(全23

    万次阅读 多人点赞 2019-06-09 00:21:59
    设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七:适配器模式、装饰器模式、代理模式、外观模式、桥接模式...
  • java设计模式(23)详解

    万次阅读 2017-08-15 08:32:41
    设计模式(Design Patterns)  ——可复用面向对象软件的...使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化
  • JAVA的23种设计模式

    千次阅读 2016-03-23 18:01:11
    设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统...
  • 初探Java设计模式4:JDK中的设计模式

    千次阅读 2017-05-15 11:03:57
    本文主要是归纳了JDK中所包含设计模式包括作用和其设计类图。 首先来个总结,具体的某个模式可以一个一个慢慢写,希望能对研究JDK和设计模式有所帮助。 一、设计模式是什么 (1)反复出现问题的解决方案 (2)...
  • Java设计模式之策略模式

    万次阅读 多人点赞 2015-04-13 07:20:41
    本文属于23种设计模式系列。 介绍的是策略模式。
  • JAVA设计模式--适配器模式

    万次阅读 2016-08-28 20:42:19
    适配器(Adapter)模式又叫做包装( Wrapper )模式,是由GOF提出的23种设计模式中的一结构型设计模式,Adapter模式的设计意图:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作.....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 390,812
精华内容 156,324
关键字:

包含3种设计模式的java代码

java 订阅