01.设计原则 & 设计模式

一、七大设计原则:

    1、单一职责原则(Single Responsibility Principle):一个类只负责一项职责。一个类(或者大到模块,小到方法)职责越多,它被复用的可能性越小。类的职责有:数据职责和行为职责。数据职责通过属性体现,行为职责通过方法体现。具体处理方法就是高内聚、低耦合。把不同的职责分离成不同的类。类不要过于庞大。

    2、开闭原则(Open close Principle):开放对外扩展,关闭对内修改。设计模块时,使得该模块可以在不被修改的前提下进行扩展。一般使用抽象化的设计原则。扩展时,仅仅是对抽象类的一个实现与扩展。抽象化是开闭原则的关键,或者说是可变性封装原则,即把经常改动的模块抽象化,并封装成抽象类,如果拓展功能的话,仅仅继承抽象类并实现即可。

    3、里氏替换原则(Liskov Substitution Principle):所有能使用基类的地方,必须可以透明地使用派生类。派生类的功能是对基类的一个拓展,派生类包含了基类的所有特征,并在者基础上进行拓展。即软件中如果能够使用基类对象,那么一定能够使用其子类对象。它是实现开闭原则的一个重要手段。程序中尽量使用基类或者抽象类实现对对象的定义,运行时根据需要使用派生类对基类进行替换。

    4、依赖倒置原则(Dependence Inversion Principle):高层模块不应该依赖低层模块,它们都应该依赖抽象。抽象不应该依赖于细节,细节应该依赖于抽象定义。针对接口或抽象类编程而不是实现或具体类,即代码要依赖于抽象的类而不是具体的类。该原则也是实现开闭原则的一个重要手段。子类型能够替换掉它们的父类型。

    5、接口隔离原则(Interface Segregation Principle):大接口应该分解成小接口,客户端不必依赖于它不需要的接口。类似于单一职责原则。不要让接口臃肿。一个接口只代表一个角色,接口仅仅提供客户端需要的行为。类之间的相互依赖应建立在最小的接口上。

    6、合用复用原则(Composite/Aggregate Reuse Principle):新对象中,尽量使用组合或聚合方式实现功能,而非继承。继承会使得类之间的耦合度过高!必须使用继承时,要严格的遵循里氏代换原则。即尽量使用组合和聚合少用继承的关系来达到复用的原则。

    7、迪米特法则(Principle Of Least Knowledge):最少知识原则。一个对象应尽可能少的与其他对象发生相互作用,对象间保持最少的了解。即:如果两个类间无需直接通信,则这两个类就不应当发生直接的相互作用。如果一个类需要调用另一个类的某一方法,需要通过第三者转发这个调用。相互通信的对象必须是:

①、当前对象本身(this); 

②、以参数形式传入到当前对象方法中的对象; 

③、当前对象的成员对象; 

④、如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友; 

⑤、当前对象所创建的对象。 



二、24种设计模式:

    1、设计模式是一套被反复使用,多数人知晓的经过分类的、代码设计经验的总结。它提高了代码可重用性,让代码更容易被他人理解,保证代码可靠性。

    2、种类与分类:

种类

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

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

        行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

        3、设计模式简述:

        1、策略模式:定义了算法家族并分别封装,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。

        2、装饰模式:动态给一个对象添加有一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。

        3、代理模式:为其他对象提供一种代理以控制对这个对象的访问。

        4、工厂模式:定义一个拥有创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。

        5、抽象工厂模式:提供了一个创建一些列相关或相互依赖对象的接口,而无需指定它们具体的类。

        6、模板模式:定义一个操作中算法的骨架,延迟一些步骤到子类中。子类不改变算法的结构,即可重定义该算法的某些特定步骤。

        7、外观模式:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

        8、建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

        9、观察者模式:定义一对多的依赖关系,让多个观察者对象同时监听某一主题对象。主题对象状态变化时,会通知所有观察者对象,使它们能够自动更新自己。

        10、原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

        11、状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

        12、适配器模式:将一个类的接口转换成客户希望的另外一个接口。使原本由于接口不兼容而不能一起工作的类可以一起工作。

        13、备忘录模式:不破坏封装性的同时,捕获一个对象的内部状态,并在该对象之外保存此状态。方便之后对象恢复到那个状态。

        14、组合模式:将对象组合成树形结构以表示“部分--整体”的层次结构。令用户对单个对象和组合对象的使用具有一致性。

        15、迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。

        16、单例模式:一个类仅有一个实例,使它们都可以独立地变化。

        17、桥接模式:将抽象部分与它的实现部分分离,使它们都可以独立地变化。

        18、命令模式:将一个请求封装为一个对象,用不同的请求对客户进行参数化。对请求排队,或记录请求日志,以及支持可撤销的操作。

        19、职责链模式:使多个对象都有机会处理请求。避免发送者和接受者之间耦合,将这个对象连成一条链传递该请求,直到有对象处理它。

        20、中介者模式:用中介对象封装一系列的对象交互。对象间无需显式地相互引用。耦合松散,可以独立地改变它们间的交互。

        21、享元模式:使用共享技术有效地支持大量细粒度的对象。

        22、解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示中解释语言汇中的句子。

        23、访问者模式:表示一个作用于某对象结构中的各元素的操作。不改变各元素的类的前提下,可以定义作用于这些元素的新操作。



三、常见设计模式:

    1、单例模式:一个程序中有且只能有一个对象的设计模式。它有 懒汉模式、饿汉模式 两种模式。

    ①、饿汉模式与实现:在类被加载时,自动创建单例的实例对象。不管用户是否会去调用该成员。

            Ⅰ、私有化类的构造方法。private

            Ⅱ、提供静态成员并初始化来保存唯一的实例。static

            Ⅲ、提供静态获取成员的方法来获取实例。static

    ②、懒汉模式与实现:首次调用类的方法时,会创建单例实例对象。后面再重复调用时,直接获取对象。

            Ⅰ、私有化类的构造方法。private

    ③、两者区别:

        饿汉模式:加载类时慢,运行时获取对象速度快。且是线程安全的。

        懒汉模式:加载类时快,运行时获取对象速度慢。但非线程安全的,有可能创建多个实例对象。所以需要使用线程锁。

    2、工厂模式:实例化对象,用工厂代理new操作。

    ①、几种工厂模式:

        Ⅰ、简单工厂模式:一个模块仅需一个工厂类,没有必要把它产生出来,使用静态的方法。

        Ⅱ、 多个工厂类:每个具体的产品类都对应一个创建者,每个创建者独立负责创建对应的产品对象,非常符合单一职责原则。

        Ⅲ、代替单例模式:单例模式的核心要求就是在内存中只有一个对象,通过工厂方法模式也可以只在内存中生产一个对象。

        Ⅳ、延迟初始化:ProductFactory 负责产品类对象的创建工作,并且通过prMap变量产生一个缓存,对需要再次被重用的对象保留。

    ②、抽象工厂模式:抽象工厂 => 实体工厂 => 抽象产品 => 实体产品。为创建一组相关或相互依赖的对象提供接口,无须指定具体类。

        Ⅰ、定义一个接口创建对象,让子类决定哪些类需要实例化。

        Ⅱ、工厂方法把实例化的工作推迟到了子类中去实现。

        Ⅲ、调用者直接调用工厂,由工厂创建对象,调用者不需要知道工厂内部的实现机制。

        Ⅳ、延迟初始化。

    3、代理模式:为其他对象提供代理,以控制对这个对象的访问。代理对象起中介作用,可去掉或增加一些服务。它可分为:

        ●、抽象主题类:可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求。

        ●、具体类:是被委托、被代理的角色。是业务逻辑的具体执行者。

        ●、代理类:即做委托类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并在真实主题角色处理完毕前后做预处理和善后。

    ①、应用场景:

        Ⅰ、远程代理: 为不同地址空间的服务器提供局域网代理。(FQ,监控多个店铺的摄像头应用)

        Ⅱ、虚拟代理: 根据需要将一个资源消耗很大的对象进行延迟,真正需要时再进行创建。(网页中的图片或者视频异步加载)

        Ⅲ、保护代理: 增加一些权限,提供对原有对象的保护。(权限控制)

        Ⅳ、智能代理:提供目标对象额外的一些服务。(火车票代售点,中介)

    ②、代理实现的方式:

        Ⅰ、静态代理:已知代理类的情况下,代理和被代理的对象在代理前是确定的,都是实现相同接口或者继承相同的类。调用者直接调用真实角色,不用关心代理是否存在,其代理的产生由真实角色决定。即 要从真实角色查找到代理角色,不允许直接访问真实角色。 代理的管理由真实角色自己完成。使用方式如下:

            1、继承方式:

                    ①、添加一个功能接口,提供一个功能方法。

                    ②、使用目标类实现功能接口,实现功能方法。

                    ③、使用代理类继承目标类并重写功能方法,使用  super.父类功能方法。

            2、包含/合成/聚合方式:

                    ①、添加一个功能接口,提供一个功能方法。

                    ②、使用目标类,实现功能接口,并实现功能方法。

                    ③、添加一个代理类,增加一个带参的构造方法,增加一个方法,使用目标类对象调用功能方法。

            3、两种实现方式的对比:

                    ①、继承方式:代理类和被代理类耦合度高,不便于扩展。每次增加新的代理都必须重新添加新的代理类。成本较高。

                    ②、聚合方式:代理类和被代理类耦合度低,便于替换被代理类的对象,更易于复用。

                    ③、面向对象的基本原则中,推荐多使用聚合而不是继承。聚合方式更适合代理模式。

        Ⅱ、动态代理:(JDK 动态代理)根据被代理的接口生成所有的方法,被代理的类必须要实现一个接口。两条线路独立发展。动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。通知Advice从另一个切面切入,最终在高层模块也就是Client进行耦合,完成逻辑的封装任务。它是横切面编程,在不改变我们已有代码结构的情况下增强或控制对象的行为。该模式下,调用者只知道代理而不用知道真实的角色。真实角色的修改对高层模块没有影响,只需要实现接口对应的方法。适用于对扩展性要求较高的场合。 使用方式如下:

            1、添加一个功能接口,提供功能方法。

            2、使用目标类,实现目标功能接口,并实现功能方法。

            3、添加动态代理类,实现 InvocationHandler 接口,添加带有功能接口对象的构造方法,重写 InnovationHandler 中 invoke 方法:

                    Object obj = method.invoke(this.功能对象,args);

            4、获取功能接口对象,获取动态代理类对象:

                    ①、功能对象 = Proxy.newProxyInstance(代理类对象.getClass().getClassLoader(),被代理类对象.getClass().getInterfaces(),动态代理类对象);

                    ②、功能对象 = Proxy.newProxyInstance(代理类对象.getClass().getClassLoader(),new Class[]{被代理类.class} ,动态代理类对象);

            5、使用动态代理,须实现 InvocationHandler 接口,InvocationHandler 接口位于 java.lang.reflect 包下。

                    InvocationHandler 接口中只有一个方法:Object invoke(Object proxy,Method  method,Object[] args)。

                    proxy : 被代理类的对象。method : 被代理类的方法。args : 被代理的方法的参数。

            6、调用动态代理,需使用 Proxy.newProxyInstance()静态方法:

                    Proxy.newProxyInstance(loader,interfaces,handler)

                    loader : 代理类类加载器。interfaces : 被代理类实现的接口。handler : 动态代理类的实现类

            7、动态代理的好处:减少编程的工作量,加入要实现多个代理的逻辑,只要写多个代理处理器就可以了,无需每种方式都写一个代理类。系统扩展性和维护性增强。

    4、适配器模式:将一个类的接口转换为客户希望的另外一个接口。即让原本接口不匹配,不能一起工作的类可以一起工作。

        ①、组合方式(对象适配器):

            Ⅰ、添加一个元接口,增加功能方法    添加实现类,并重写功能方法。

            Ⅱ、添加一个目标接口,增加功能方法    添加实现类,并重写其功能方法。

            Ⅲ、添加适配器类 实现元接口,添加带有目标接口对象的构造方法,重写元方法,使用目标接口对象调用目标方法。

        ②、继承方式(类适配器):

            Ⅰ、添加一个元接口,增加功能方法    添加实现类,并重写功能方法。

            Ⅱ、添加一个目标接口,增加功能方法    添加实现类,并重写其功能方法。

            Ⅲ、添加适配器类 继承目标接口的实现类  并实现元接口,重写元接口中的方法,采用super.目标方法()调用。

        ③、区别: 

            Ⅰ、组合方式(对象适配器):把"被适配器"组一个对象组合到适配器中,以修改目标接口包装被适配器。

            Ⅱ、继承方式(类适配器):通过多重继承不兼容的接口,实现对目标接口的匹配,单一为某个类的实现而适配。

            Ⅲ、特点: 透明、重用、低耦合。用一个已经存在类的接口时,如果接口或方法与你的要求不同时,可以采用适配器模式。

    5、策略模式:定义算法家族并分别封装,让它们之间可以互相替换。算法变化不会影响调用算法的用户。策略算法是相同行为的不同实现。

        ①、实现步骤:

            Ⅰ 、添加抽象的策略父类 Strategy。

            Ⅱ 、添加实现抽象类的子类。

            Ⅲ 、定义 Factory 工厂生产策略对象。

            Ⅳ、定义 Content 调用功能。

        ②、优点:

            Ⅰ 、提供了管理相关的算法家族的办法。

            Ⅱ 、提供了可以替换继承关系的办法。

            Ⅲ 、避免使用多重条件转移的语句。

        ③、应用场景:多个类只区别在表现行为不同,可以使用 Strategy 模式,在运行时动态选择具体要执行的行为。

    6、模板模式:定义一个操作中算法的骨架,步骤在子类中实现。子类不改变算法结构,即可重定义该算法的某些特定步骤。为防止恶意操作,一般模板方法都加上final关键字,不允许被覆写。

        ①、基本方法:

            Ⅰ 、在模板方法中添加可被子类重写,方法返回值为 Boolean,来判断是否需要执行特定的操作。子类实现方法并在模板调用。

            Ⅱ 、具体步骤:

                1、多个子类有公有的方法,并且逻辑基本相同时。

                2、重要、复杂的算法,把核心算法设计为模板方法,其余功能则由各个子类实现。

                3、重构时,把相同的代码抽取到父类中,然后通过钩子函数(见Ⅰ)约束其行为。

        ②、优缺点:

            Ⅰ 、在一个类中形式化地定义算法,而由它的子类实现细节的处理。

            Ⅱ 、是一种代码复用的基本技术。

            Ⅲ 、反向的控制结构。“好莱坞法则”,即父类调用子类,通过对子类的扩展增加新的行为,符合“开闭原则”。

            Ⅳ、但会导致类的个数增加,但更符合“单一职责原则”。

        ③、适用场景:一次实现一个算法的不变部分,并将可变的行为留给子类来实现,需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。

    7、建造者模式:将复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

        ①、组成部分:

            Ⅰ、产品类:通常实现了模板模式,即有模板方法和基本方法。

            Ⅱ、抽象建造者:父类方法等。一般由子类实现并组建规范的产品。

            Ⅲ、具体建造者:实现抽象类定义的所有方法,并返回组建好的对象。

            Ⅳ、导演类:安排已有模块的顺序,然后告诉Builder开始建造。

        ②、使用场景:

            Ⅰ、相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式。

            Ⅱ、多个部件或零件,都可以装配到一个对象中。但产生的运行结果又不相同时,可以使用该模式。

            Ⅲ、产品类非常复杂,或类中的调用顺序不同产生了不同的效能,适合用建造者模式。

        ③、建造者模式与工厂模式的不同:

            Ⅰ、建造者模式:基本方法的调用顺序安排,这些基本方法已经实现了,顺序不同产生的对象也不同;

            Ⅱ、工厂方法:主要用于创建。组装顺序则不是它关心的。

        8、原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。实际上就是实现Cloneable接口,重写clone()方法。

        ①、特点:

            Ⅰ、性能优良。原型模式是内存二进制流的拷贝,比new对象性能好很多,尤其在循环体内产生大量对象的情况下。

            Ⅱ、逃避构造函数的约束:既是优点也是缺点,直接在内存中拷贝,不会执行构造函数。

        ②、使用场景:

            Ⅰ、资源优化:类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。

            Ⅱ、性能和安全要求:new产生对象需要非常繁琐的数据准备或访问权限。

            Ⅲ、一个对象多个修改者:一个对象要供其他对象访问,调用者们可能都需要修改其值。原型模式拷贝多个对象供调用者使用。

        ③、浅拷贝和深拷贝:

            Ⅰ、浅拷贝:Object类提供的方法clone只拷贝本对象,不拷贝对象内部的数组、引用对象等。它们还是指向原生对象的内部元素地址。其他原始类型(int、long、char、string)会被拷贝。

            Ⅱ、深拷贝:对私有的类变量进行独立的拷贝。如:thing.arrayList = (ArrayList<String>)this.arrayList.clone();

        ④、原型模式下,引用的成员变量两种情况下不会被拷贝:

            Ⅰ、类的成员变量,而非方法内变量。

            Ⅱ、必须是一个可变的引用对象,而非一个原始类型或不可变对象。

        9、中介者模式:用中介对象封装一系列的对象交互,适用于多个对象紧密耦合的情况。紧密耦合的标准是:在类图中出现了蜘蛛网状结构,即每个类都与其他的类有直接的联系。

            ①、组成部分:

                Ⅰ、抽象中介者:定义统一的接口,用于各同事角色之间的通信。

                Ⅱ、具体中介者:通过协调各同事角色实现协作行为。它必须依赖于各个同事角色。

                Ⅲ、同事:同事间通信时,需通过中介者角色协作。同事类行为分为两种:

                    1、同事本身的行为(自发行为),与其他的同事类或中介者没有任何依赖。比如改变对象本身的状态,处理自己的行为等。

                    2、必须依赖中介者才能完成的行为,叫做依赖方法。

            ②、ps:

                Ⅰ、使用同事类注入而非抽象注入的原因:抽象类中不具有每个同事类必须要完成的方法。即每个同事类中的方法各不相同。

                Ⅱ、同事类要使用构造函数注入中介者,因为同事类必须有中介者。中介者使用getter/setter方式注入同事类,因为中介者却可以只有部分同事类。




https://www.cnblogs.com/yunfeioliver/p/9306355.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345