精华内容
下载资源
问答
  • 设计模式7大原则

    千次阅读 2018-12-11 11:21:37
    文章目录面向对象设计原则概述1.单一职责原则单一职责定义单一职责举例分析2...合成复用原则合成复用原则简介7.迪米特法则迪米特法则简介8.总结 面向对象设计原则 概述 对于面向对象软件系统的设计而言,在支持可...

    面向对象设计原则

    概述

    对于面向对象软件系统的设计而言,在支持可维护性的同时,提高系统的可复用性是一个至关重要的问题,如何同时提高一个软件系统的可维护性和可复用性是面向对象设计需要解决的核心问题之一。在面向对象设计中,可维护性的复用是以设计原则为基础的。每一个原则都蕴含一些面向对象设计的思想,可以从不同的角度提升一个软件结构的设计水平。 面向对象设计原则为支持可维护性复用而诞生,这些原则蕴含在很多设计模式中,它们是从许多设计方案中总结出的指导性原则。面向对象设计原则也是我们用于评价一个设计模式的使用效果的重要指标之一,在设计模式的学习中,大家经常会看到诸如“XXX模式符合XXX原则”、“XXX模式违反了XXX原则”这样的语句。
    最常见的7种面向对象设计原则如下表所示:

    1.单一职责原则

    单一职责定义

    一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因

    从定义中不难思考,一个类的所做的事情越多,也就越难以复用,因为一旦做的事情多了,职责的耦合度就变高了所以我们根据这个原则应该将不同职责封装在不同类中,不同的变化封装在不同类中。从我们平常的开发中不难发现,如果一个类或者方法接口等等只做一件事,那么可读性很高,并且复用性也很高,并且一旦需求变化,也容易维护,假如你一个类糅杂多个职责,那么很难维护。

    单一职责举例分析

    从实际业务来剥离一个例子:现在有这么一种情况,某租车平台个人模块类涉及多个方法,有如下登录、注册、支付宝押金支付、微信押金支付、支付宝套餐支付、微信套餐支付、整个结构如下:

     	 /**
         * 个人模块
         */
        @Controller
        public class userController{
            /**
             * 登录
             */
            public void login(){
            }
    
            /**
             * 注册
             */
            public void register(){
            }
            /**
             * 押金支付(阿里)
             */
            public void payAliDeposit(){
            }
    
            /**
             * 押金支付(微信)
             */
            public void payWXDeposit(){
            }
    
            /**
             * 套餐支付(阿里)
             */
            public void payAliPackage(){
            }
    
            /**
             * 套餐支付(微信)
             */
            public void payWXPackage(){
            }
        }
    

    我们可以看到很多功能都糅杂在一起,一个类做了那么多事情,很臃肿,别提维护,就连找代码都很困难,所以我们可以对这个UserController进行拆解,与此同时我们应该分包,比如这个应该在xxx.xxx.userMoudule下面,可能支付相关的有公共的方法,登录抑或也有公共的方法,那边抽成公共服务去调用。

    public class LoginController(){}
    public class registerController(){}
    public class depositPayController(){
        // 支付宝支付
        // 微信支付
    }
    public class packagePayController(){
        // 支付宝支付
        // 微信支付
    }
    

    整个方案实现的目的就是为了解决高耦合,代码复用率低下的问题。单一职责理解起来不难,但是实际操作需要根据具体业务的糅杂度来切割,实际上很难运用。

    2.开闭原则

    开闭原则简介

    开闭原则是面向对象的可复用设计的第一块基石,它是最重要的面向对象设计原则,定义如下:

    一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。

    软件实体包括以下几个部分:

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

    注意:开闭原则是指对扩展开放,对修改关闭,并不是说不做任何的修改

    开闭原则的优势

    • 可以使原来的测试代码依旧可以运行,只需要对扩展的代码进行测试即可
    • 可以提高代码的复用性
    • 可以提高系统的维护性

    ###如何使用开闭原则

    • 抽象约束
      • 通过接口或者抽象类约束扩展,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法;
      • 参数类型、引用对象尽量使用接口或者抽象类,而不是实现类;(针对抽象编程)
      • 抽象层尽量保持稳定,一旦确定即不允许修改。
    • 元数据控制模块行为
      通俗来说就是通过配置文件来操作数据,spring的控制反转就是一个很典型的例子。
    • 约定优于配置
    • 封装变化
    • 将相同的变化封装到一个接口或者类中
    • 将不同的变化封装到不同的类或者接口中(单一职责的体现)

    案例

    某公司开发的租车系统有一个押金支付功能,支付方式有支付宝、阿里支付,后期可能还有银联支付、易支付等等,原始的设计方案如下:

    1544321940668

    // 客户端调用-押金支付选择支付手段
    public class DepositPay {
    
        void pay(String type){
            if(type.equals("ali")){
                AliPay aliPay = new AliPay();
                aliPay.pay();
            }else if(type.equals("wx")){
                WXPay wxPay = new WXPay();
                wxPay.pay();
            }
        }
    }
    // 支付宝支付
    public class AliPay {
        public void pay() {
            System.out.println("正在使用支付宝支付");
        }
    }
    // 微信支付
    public class WXPay{
        public void pay() {
            System.out.println("正在使用微信支付");
        }
    }
    
    

    在以上代码中,如果需要增加银联支付,如YLPay,那么就必须要修改DepositPay中的pay方法的源代码,增加新的判断逻辑,违反了开闭原则(对修改关闭,对扩展开放,注意这边的银联支付相当于扩展,所以它没有违反规则),所以现在必须重构此代码,让其遵循开闭原则,做法如下:

    1. 增加一个接口,使得各种具体支付实现其接口
    2. DepositPay类针对接口编程,由客户端来决定具体使用哪种支付方式

    重构后的图如下所示:

    1544324553495

    在上图中我们引入了接口Pay,定义了pay方法,并且DepositPay是针对接口编程,通过setPayMode()由客户端来实例化具体的支付方式,在DepositPay的pay()方法中调用payMode对象来支付。如果需要增加新的支付方式,比如银联支付,只需要让它也实现Pay接口,在配置文件中配置银联支付即可,依赖注入是实现此开闭原则的一种手段,在这里不赘述,源码如下:

    public interface Pay {
        // 支付
        void pay();
    }
    public class AliPay implements Pay {
        @Override
        public void pay() {
            System.out.println("正在使用支付宝支付");
        }
    }
    public class WXPay implements Pay{
        @Override
        public void pay() {
            System.out.println("正在使用微信支付");
        }
    }
    // 客户端调用-押金支付选择支付手段
    public class DepositPay {
        // 支付方式 (这边可以通过依赖注入的方式来注入)
        // 支付方式可以写在配置文件中
        // 现在不管你选用何种方式,我都不需要更改
        @Autowired
        Pay payMode;
        void pay(Pay payMode){
            payMode.pay();
        }
    }
    

    因为配置文件可以直接编辑,且不需要编译,所以一般不认为更改配置文件是更改源码。如果一个系统能做到只需要修改配置文件,无需修改源码,那么复合开闭原则。

    3.里氏代换原则

    里氏替换原则简介

    Barbara Liskov提出:

    标准定义:如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1代换o2时,程序P的行为没有变化,那么类型S是类型T的子类型。

    上面的定义可能比较难以理解,简单理解就是所有引用基类(父类的)地方都可以用子类来替换,且程序不会有任何的异常。但是反过来就不行,所有使用子类的地方则不一定能用基类来替代,很简单的例子狗是动物,不能说动物是狗,因为可能还有猫。。。。

    里氏替换原则是实现开闭原则的重要方式之一,由于使用基类的所有地方都可以用子类来替换,因此在程序中尽量使用基类来定义对象,在运行时确定其子类类型

    里氏替换原则约束

    • 子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。
    • 子类中可以添加特有方法(父类中不存在),此时则无法在以父类定义的对象中使用该方法,除非在使用的时候强转基类成子类进行调用。
    • 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
    • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

    所以我们在运用里氏替换原则的时候,尽量把父类设计为抽象类或者接口,让子类继承父类或者实现接口并实现在父类中声明的方法,运行时,子类实例替换父类实例,我们可以很方便地扩展系统的功能,同时无须修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现。里氏代换原则是开闭原则的具体实现手段之一。

    里氏替换原则实战

    某租车系统客户分为普通用户(customer)和VIP客户(VIPCustomer),系统需要提供一个根据邮箱重置密码的功能。原始设计图:

    1544358831335

    在编写重置密码的时候发现,业务逻辑是一样的,存在着大量的重复代码,而且还可能增加新的用户类型,为了减少代码重复性,使用里氏替换原则进行重构:

    1544358831335

    图上重置密码交由ResetPassword类去处理,只需要传入Customer类即可,不管任何类型的Customer类,只要继承自Customer,都可以使用里氏替换原则进行替换,假如有新的类型,我们只需要在配置文件中注入新的类型即可。代码如下(简单意会一下):

    // 抽象基类
    public abstract class Customer {
    }
    public class CommonCustomer  extends Customer{
    }
    public class VIPCustomer  extends Customer{
    }
    // 重置密码逻辑在这里实现,只需要传入对应的类型即可
    public class ResetPassword {
        void resetPassword(Customer customer){
        }
    }
    
    

    里氏替换原则是实现开闭原则不可或缺的手段之一,在本例中,通过传递参数使用基类对象,针对抽象编程,从而满足开闭原则。

    4.依赖倒转原则

    依赖倒转原则简介

    依赖倒转原则(Dependency Inversion Principle, DIP):抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。

    可以通俗的定义为两种:

    1. 高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。
    2. 抽象不应该依赖于具体实现,具体实现应该依赖于抽象。

    要求我们在设计程序的时候尽量使用层次高的抽象层类,即使用接口和抽象类进行变量的声明、参数类型声明、方法返回类型声明以及数据类型转换等等,同时要注意一个具体类应该只实现抽象类或者接口中存在的方法,不要给出多余的方法,这样抽象类将无法调用子类增加的方法.我们可以通过配置文件来写入具体类,这样一旦程序行为改变,可直接改变配置文件,而不需要更改程序,重新编译,通过依赖倒转原则来满足开闭原则。

    在实现依赖倒转原则时,我们需要针对抽象层编程,而将具体类的对象通过依赖注入(DependencyInjection, DI)的方式注入到其他对象中,依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。常用的注入方式有三种,分别是:构造注入,设值注入(Setter注入)和接口注入

    依赖倒转原则实例

    这部分可以参照上面开闭原则案例,可以从那例子中看出,开闭原则,依赖倒转原则,里氏替换原则同时出现了,可以说`开闭原则是我们要实现的目标,而里氏替换原则是实现手段之一,而同时里氏替换原则又是依赖倒转原则实现的基础,因为加入没有这个理论,依赖倒转原则是不成立的,无法针对抽象编程,要注意这3个原则基本都是同时出现的。

    5.接口隔离原则

    接口隔离原则简介

    接口隔离原则的两个定义:

    1:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口

    **2:类间的依赖关系应该建立在最小的接口上 **

    接口的含义:

    1. 一个接口代表一个角色,不应该将不同的角色都交给一个接口,因为这样可能会形成一个臃肿的大接口;
    2. 特定语言的接口,表示接口仅仅是提供客户端需要的行为,客户端不需要的行为则隐藏起来,应当为客户端提供尽可能小的单独的接口,而不要提供大的总接口。

    根据接口隔离原则,我们可明白,每个接口都应只承担一种相对独立的角色,不干不该干的事情.

    实例演示

    场景:模拟动物平时的动作,当然也包括人,最初的设计就是一个总接口IAnimal,里面定义动物会有的一些动作。

    1544426255953

    代码如下:

     public interface IAnimal{
            /**
             * 吃饭
             */
            void eat();
    
            /**
             * 工作
             */
            void work();
    
            /**
             * 飞行
             */
            void  fly();
        }
     public class Tony implements IAnimal{
    
            @Override
            public void eat() {
                System.out.println("tony吃");
            }
    
            @Override
            public void work() {
                System.out.println("tony工作");
            }
    
            @Override
            public void fly() {
                System.out.println("tony不会飞");
            }
        }
    public class Bird implements IAnimal{
    
            @Override
            public void eat() {
                System.out.println("鸟吃");
            }
    
            @Override
            public void work() {
                System.out.println("鸟工作");
            }
    
            @Override
            public void fly() {
                System.out.println("鸟飞");
            }
        }
        
    

    根据上面的写法发现Tony需要实现飞的接口,这很明显不仅仅是多余,而且不合理,因此需要通过接口隔离原则进行重构:

    1544428677838

    /**
     * 抽象动物的行为
     */
    public interface IAnimal {
        /**
         * 吃饭
         */
        void eat();
    
        /**
         * 睡觉
         */
        void sleep();
    }
    /**
     * 高级动物人 的行为
     */
    public interface IAdvancedAnimalBehavior {
        /**
         * 打牌
         */
        void playCard();
    
        /**
         * 骑车
         */
        void byBike();
    }
    /**
     * 低级动物的行为
     */
    public interface IJuniorAnimalBehavior {
        /**
         * fly
         */
        void fly();
    }
    /**
     * 实现高级动物人的共通方法
     */
    public class AbstractAdvancedAnimal implements IAnimal {
        @Override
        public void eat() {
            System.out.println("人吃");
        }
    
        @Override
        public void sleep() {
            System.out.println("人睡");
        }
    }
    /**
     * 实现低级动物人的共通方法
     */
    public class AbstractJuniorAnimal implements IAnimal {
        @Override
        public void eat() {
            System.out.println("动物吃");
        }
    
        @Override
        public void sleep() {
            System.out.println("动物睡");
        }
    }
    // tony
    public class Tony extends AbstractAdvancedAnimal implements IAdvancedAnimalBehavior {
        @Override
        public void playCard() {
            System.out.println("tony打牌");
        }
    
        @Override
        public void byBike() {
            System.out.println("tony骑车");
        }
    }
    // 鸟
    public class Bird extends AbstractJuniorAnimal implements IJuniorAnimalBehavior{
        @Override
        public void fly() {
            System.out.println("鸟飞");
        }
    }
    
    
    

    重构之后,首先定义了一个总的动物接口的大类,然后分别使用了两个抽象类(一个是高级动物,一个是低级动物)分别去实现这些公共的方法,实现中可以抛出异常,表明继承此抽象类的类可以选择性的重写,可不重写。之后再定义了两个行为接口表明高级动物和低级动物所特有的,这样使得接口之间完全隔离,动物接口不再糅杂各种各样的角色,当然接口的大小尺度还是要靠经验来调整,不能太小,会造成接口泛滥,也不能太大,会背离接口隔离原则。

    6.合成复用原则

    合成复用原则简介

    合成复用原则(Composite Reuse Principle, CRP):尽量使用对象组合,而不是继承来达到复用的目的。

    通过合成复用原则来使一些已有的对象使之成为对象的一部分,一般通过组合/聚合关系来实现,而尽量不要使用继承。因为组合和聚合可以降低类之间的耦合度,而继承会让系统更加复杂,最重要的一点会破坏系统的封装性,因为继承会把基类的实现细节暴露给子类,同时如果基类变化,子类也必须跟着改变,而且耦合度会很高。

    7.迪米特法则

    参考:https://www.cnblogs.com/muzongyan/archive/2010/08/05/1793454.html
    参考:https://blog.csdn.net/lovelion/article/details/7537584
    参考:https://blog.csdn.net/qq_34966814/article/details/79475977

    如果有小伙伴觉得我写的不错的话可以关注一下我的博客,我会一直持续更新,也可以支持一下我的公众号哦:java架构师小密圈,会分享架构师所必须深入研究的技术,比如netty,分布式,性能优化,spring源码分析,mybatis源码分析,等等等,同时还会分享一些赚钱理财的小套路哦,欢迎大家来支持,一起学习成长,程序员不仅仅是搬瓦工!
    公众号:分享系列好文章
    java架构师小密圈

    交流群:群友互相分享资料
    java架构师小密圈

    展开全文
  • 设计模式大原则

    千次阅读 2019-03-17 16:34:06
    设计模式是构建框架的基础,要想写出优秀的代码,必须要有写代码的大局观意识。 七设计原则 1.开闭原则:用抽象构建架构,用实现扩展细节 2.依赖倒置原则:高层模块不应该依赖于底层模块,二者都应该依赖其抽象...

    设计模式是构建框架的基础,要想写出优秀的代码,必须要有写代码的大局观意识。

    七大设计原则

    1.开闭原则:用抽象构建架构,用实现扩展细节

    2.依赖倒置原则:高层模块不应该依赖于底层模块,二者都应该依赖其抽象

    3.单一职责原则:单个接口或类不应该有多个职责,应该尽可能的划分职责,通过组合的方式,完成更为复杂的业务

    4.接口隔离原则:一个接口不要包含过多的职责,应合理划分,跟单一职责原则相辅相成

    典型场景:动物、人、鸟,人和鸟都会吃,人会走路,鸟会飞,应该把走路和飞这两个行为抽象成接口,通过组合的方式让人拥有走路的行为,让鸟拥有飞的行为。再细划分,人有多个走路姿势,鸟有多个飞行方式,可以分别继承走路和飞的抽象行为扩展其具体的行为
    

    5.迪米特法则:也就最少知道原则,一个对象尽量让其它对象保持最少的了解

    典型场景:我点外卖,我只关心外卖员,不关系具体的店。我的类中只依赖外卖员,不会依赖具体的店。是不是静态代理。

    6.里氏替换原则:在引用父类的地方,都可以替换为其子类。从而可以实现子类间的动态切换。换句话说就是要有面向接口的编程思维。结合“开闭原则”,完美

    7.合成复用原则:多用组合,少用继承

    总结:活学活用,切勿生搬硬套。

    展开全文
  • java设计模式大原则

    千次阅读 2018-06-05 10:26:33
    当一个接口太时,我们需要把他拆分成更小的接口,但不能违反单一职责原则,每个接口应该承担一种相对独立的角色,不该干的事情不干,该干的事情都要干。 6.迪米特法则 ( Law Of Demeter )   -一个实体应当尽量...
    导图设计:


    1.开闭原则 (Open Close Principle)
        - 对扩展开放,对更改关闭
       -保证以前代码的准确性,使开发者更专注于新扩展的代码上

    2.单一职责原则 Single Responsibility Principle
        - 一个类只负责一个功能领域的职责
        -降低类的复杂度,当修改一个功能时,降低对其他功能的影响,提供类的可读性

    3.里氏替换原则 Liskov Substitution Principle
        -任何基类出现的地方,子类一定可以出现
        -在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象,开闭原则实现的手段之一

    4.依赖倒转原则 Dependence Inversion Principle
       -针对接口编程,抽象不依赖于细节,细节应依赖于抽象
        -多数情况下,开闭原则,里氏替换原则,依赖倒转原则会同时出现,开闭原则是目标,里氏替换原则是基础,依赖倒转是手段。

    5.接口隔离原则 Interface Segregation Principle
       -使用多个专门的接口,不使用单一的总接口
        -当一个接口太大时,我们需要把他拆分成更小的接口,但不能违反单一职责原则,每个接口应该承担一种相对独立的角色,不该干的事情不干,该干的事情都要干。

    6.迪米特法则 Law Of Demeter
       -一个实体应当尽量少的与其他实体发生相互作用
        - 应该尽量减少对象之间的交互,如果两个对象之间不必彼此直接通信,那么这两个对象就不应当发生任何直接的相互作用,如果其中的一个对象需要调用另一个对象的       某一个方法的话,可以通过第三者转发这个调用。

    7.合成复用原则(Composite Reuse Principle)
       -尽量使用组合而非继承
        -就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分,新的对象通过这些对象的委派达到复用已有功能的目的


    参考:http://www.cnblogs.com/dolphin0520/p/3919839.html






    展开全文
  • 分别就是Java设计模式大原则和常用的23种设计模式了。本篇是对六大原则的整理。(最后一种是哈姆雷特)1.开闭原则(Open Close Principle)定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。 开放-...

    对于Java看到过一个很有意思的说法:Java有六大心法,23种武功招式。

    分别就是Java设计模式六大原则和常用的23种设计模式了。

    本篇是对六大原则的整理。(最后一种是哈姆雷特)

    1.开闭原则(Open Close Principle)
    定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
        开放-封闭原则的意思就是说,你设计的时候,时刻要考虑,尽量让这个类是足够好,写好了就不要去修改了,如果新需求来,我们增加一些类就完事了,原来的代码能不动则不动。这个原则有两个特性,一个是说“对于扩展是开放的”,另一个是说“对于更改是封闭的”。面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。这就是“开放-封闭原则”的精神所在
        比如,刚开始需求只是写加法程序,很快在client类中完成后,此时变化没有发生,需求让再添加一个减法功能,此时会发现增加功能需要修改原来这个类,这就违背了开放-封闭原则,于是你就应该考虑重构程序,增加一个抽象的运算类,通过一些面向对象的手段,如继承、动态等来隔离具体加法、减法与client耦合,需求依然可以满足,还能应对变化。此时需求要添加乘除法功能,就不需要再去更改client及加减法类,而是增加乘法和除法子类即可。
    绝对的修改关闭是不可能的,无论模块是多么的‘封闭‘,都会存在一些无法对之封闭的变化,既然不可能完全封闭,设计人员必须对于他设计的模块应该对哪种变化封闭做出选择。他必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离那些变化。在我们最初编写代码时,假设变化不会发生,当变化发生时,我们就创建抽象来隔离以后发生同类的变化。
         我们希望的是在开发工作展开不久就知道可能发生的变化,查明可能发生的变化所等待的时候越长,要创建正确的抽象就越困难。开放-封闭原则是面向对象设计的核心所在,遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅对程序中呈现出现频繁变化的那些部分做出抽象,然而对于应用程序中的每个部分都刻意地进行抽象同样不是一个好主意,拒绝不成熟的抽象和抽象本身一样重要。开放-封闭原则,可以保证以前代码的正确性,因为没有修改以前代码,所以可以保证开发人员专注于将设计放在新扩展的代码上。
    简单的用一句经典的话来说:过去的事已成历史,是不可修改的,因为时光不可倒流,但现在或明天计划做什么,是可以自己决定(即扩展)的。

     

    2.里氏代换原则(Liskov Substitution Principle)
    定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。
    定义2:子类型必须能够替换掉它们的父类型。
        描述:一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别,也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化
    例子:在生物学分类上,企鹅是一种鸟,但在编程世界里,企鹅却不能继承鸟。在面向对象设计时,子类拥有父类所有非private的行为和属性,鸟会飞,但企鹅不会飞,所以企鹅不能继承鸟类。
        只有当子类可以替换掉父类,软件单位的功能不受影响时,父类才能真正被复用,而子类也能够在父类的基础上增加新的行为,正是有里氏代换原则,使得继承复用成为了可能。正是由于子类型的可替换性才使得使用父类类型的模块在无需修改的情况下就可以扩展,不然还谈什么扩展开放,修改关闭呢
    里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:
    1.子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
    2.子类中可以增加自己特有的方法。
    3.当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
    4.当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
        看上去很不可思议,因为我们会发现在自己编程中常常会违反里氏替换原则,程序照样跑的好好的。所以大家都会产生这样的疑问,假如我非要不遵循里氏替换原则会有什么后果?
    后果就是:你写的代码出问题的几率将会大大增加。

     

    3.依赖倒转原则(Dependence Inversion Principle)
    定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。即针对接口编程,不要针对实现编程
        依赖倒转其实就是谁也不要依靠谁,除了约定的接口,大家都可以灵活自如。依赖倒转可以说是面向对象设计的标志,用哪种语言来编写程序不重要,如果编写时考虑的都是如何针对抽象编程而不是针对细节编程,即程序中所有的依赖关系都是终止于抽象类或者接口,那就是面向对象的设计,反之那就是过程化的设计了。如果设计的各个部件或类相互依赖,这样就是耦合度高,难以维护和扩展,这也就体现不出面向对象的好处了。
        依赖倒转原则,好比一个团队,有需求组,开发组,测试组,开发组和测试组都是面对同样的需求后,做自己相应的工作,而不应该是测试组按照开发组理解的需求去做测试用例,也就是说开发组和测试组都是直接面向需求组工作,大家的目的是一样的,保证产品按时上线,需求是不依赖于开发和测试的。
        依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。在java中,抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。
        依赖倒置原则的中心思想是面向接口编程,传递依赖关系有三种方式,以上的说的是是接口传递,另外还有两种传递方式:构造方法传递和setter方法传递,相信用过Spring框架的,对依赖的传递方式一定不会陌生。
    在实际编程中,我们一般需要做到如下3点:
    低层模块尽量都要有抽象类或接口,或者两者都有。
    变量的声明类型尽量是抽象类或接口。
    使用继承时遵循里氏替换原则。
        总之,依赖倒置原则就是要我们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。

     

    4.接口隔离原则(Interface Segregation Principle)
       接口隔离原则的含义是:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。在程序设计中,依赖几个专用的接口要比依赖一个综合的接口更灵活。接口是设计时对外部设定的“契约”,通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
       说到这里,很多人会觉的接口隔离原则跟单一职责原则很相似,其实不然。其一,单一职责原则原注重的是职责;而接口隔离原则注重对接口依赖的隔离。其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口接口,主要针对抽象,针对程序整体框架的构建。
    采用接口隔离原则对接口进行约束时,要注意以下几点:
    1. 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
    2. 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
    3. 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
       运用接口隔离原则,一定要适度,接口设计的过大或过小都不好。设计接口的时候,只有多花些时间去思考和筹划,才能准确地实践这一原则。

     

    5.迪米特法则(Law Of Demeter)
        迪米特法则其根本思想,是强调了类之间的松耦合,类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成影响,也就是说,信息的隐藏促进了软件的复用。
        自从我们接触编程开始,就知道了软件编程的总的原则:低耦合,高内聚。无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率。低耦合的优点不言而喻,但是怎么样编程才能做到低耦合呢?那正是迪米特法则要去完成的。
        迪米特法则又叫最少知道原则,最早是在1987年由美国Northeastern University的Ian Holland提出。通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。迪米特法则还有一个更简单的定义:只与直接的朋友通信。首先来解释一下什么是直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。
    一句话总结就是:一个对象应该对其他对象保持最少的了解。

     

    6.单一职责原则(Single Responsibility Principle)
    定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责,应该仅有一个引起它变化的原因
        说到单一职责原则,很多人都会不屑一顾。因为它太简单了。稍有经验的程序员即使从来没有读过设计模式、从来没有听说过单一职责原则,在设计软件时也会自觉的遵守这一重要原则,因为这是常识。在软件编程中,谁也不希望因为修改了一个功能导致其他的功能发生故障。而避免出现这一问题的方法便是遵循单一职责原则。虽然单一职责原则如此简单,并且被认为是常识,但是即便是经验丰富的程序员写出的程序,也会有违背这一原则的代码存在。为什么会出现这种现象呢?因为有职责扩散。所谓职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2。
    遵循单一职责原的优点有:
    1.可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;
    2.提高类的可读性,提高系统的可维护性;
    3.变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。
    需要说明的一点是单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都需要遵循这一重要原则。

     

    7.组合/聚合复用原则
    就是说要尽量的使用合成和聚合,而不是继承关系达到复用的目的
    该原则就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分:新的对象通过向这些对象的委派达到复用已有功能的目的。
          其实这里最终要的地方就是区分“has-a”和“is-a”的区别。相对于合成和聚合,
    继承的缺点在于:父类的方法全部暴露给子类。父类如果发生变化,子类也得发生变化。聚合的复用的时候就对另外的类依赖的比较的少。。
    合成/聚合复用
    ① 优点:
    新对象存取成分对象的唯一方法是通过成分对象的接口;
     这种复用是黑箱复用,因为成分对象的内部细节是新对象所看不见的;
     这种复用支持包装;
    这种复用所需的依赖较少;
    每一个新的类可以将焦点集中在一个任务上;
     这种复用可以在运行时动态进行,新对象可以使用合成/聚合关系将新的责任委派到合适的对象。
    ② 缺点:
    通过这种方式复用建造的系统会有较多的对象需要管理。
    继承复用
    ① 优点:
      新的实现较为容易,因为基类的大部分功能可以通过继承关系自动进入派生类;
      修改或扩展继承而来的实现较为容易。
    ② 缺点:
      继承复用破坏包装,因为继承将基类的实现细节暴露给派生类,这种复用也称为白箱复用;如果基类的实现发生改变,那么派生类的实现也不得不发生改变;从基类继承而来的实现是静态的,不可能在运行时发生改变,不够灵活。

    展开全文
  • 设计模式大原则总结

    千次阅读 2018-09-14 08:49:09
    1.单一职责原则(Single Responsibility Principle) 目的:降低代码复杂度、系统解耦合、提高可读性 含义:对于一个类,只有一个引起该类变化的原因;该类的职责是唯一的,且这个职责是唯一引起其他类变化的原因。 ...
  • 设计模式的六大原则

    万次阅读 多人点赞 2019-05-16 17:50:03
    一、单一职责原则(Single Responsibility Principle) 二.开闭原则(Open-Closed Principle, OCP) 三、里氏代换原则(Liskov Substitution Principle, LSP) 四、依赖倒置原则(Dependence Inversion Principle,...
  • 一什么是设计模式?  设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计 模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,...
  • 软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。...
  • 设计模式6大原则.doc

    千次下载 热门讨论 2012-02-27 09:05:05
    设计模式大原则的一点总结,欢迎免费下载。
  • 深入理解设计模式-设计模式大原则

    千次阅读 多人点赞 2021-05-26 09:44:41
    深入理解设计模式-设计模式大原则 文章目录前言一、单一职责原则1.基本介绍2.注意事项和细节二、接口隔离原则1.基本介绍三、依赖倒转原则1.基本介绍2.注意事项和细节四、里氏替换原则1.基本介绍五、开闭原则1....
  • SOLID是几个重要编码原则的缩写 SRP: The Single Responsibility Principle 单一责任原则 OCP: The Open Closed Principle 开放封闭原则 LSP: The Liskov Substitution Principle 里氏替换原则 LD: The law of ...
  • 简介: c++ 设计模式(8设计原则、23中设计模式)李建忠 笔记总结 文章目录本博文的简述or解决问题?重要提示:重新认识面向对象面向对象设计原则(一共八种)将设计原则提升为设计经验C++设计模式(一共23种)本...
  • Java设计模式6大原则

    千次阅读 2019-03-01 18:50:45
    设计模式的6大原则,单一职责原则,开放封闭原则,里式替换原则,依赖导致原则,迪米特原则和接口隔离原则
  • 设计模式-七大原则(图解一目了然)

    千次阅读 多人点赞 2020-09-30 20:32:44
    你是不是还在这样写代码?当头一棒,看完本文快回去检查检查你的代码吧! 单一职责原则 接口隔离原则 依赖倒转原则 里氏替换原则 开闭原则 迪米特法则 合成复用原则
  • 补充一下面对对象设计八大原则:前五大原则设计模式的前五大原则相同,为: 1、单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,...
  • 设计模式大原则

    千次阅读 多人点赞 2018-09-06 14:38:04
    关于设计模式的六设计原则的资料网上很多,但是很多地方解释地都太过于笼统化,我也找了很多资料来看,发现CSDN上有几篇关于设计模式的六大原则讲述的比较通俗易懂,因此转载过来。  原作者博客链接:...
  • Java设计模式

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

    万次阅读 多人点赞 2018-08-12 20:34:32
    设计模式的六大原则有: Single Responsibility Principle:单一职责原则 Open Closed Principle:开闭原则 Liskov Substitution Principle:里氏替换原则 Law of Demeter:迪米特法则 Interface Segregation ...
  • 设计模式分类以及六设计原则(汇总篇)

    万次阅读 多人点赞 2018-05-22 22:36:28
    设计模式的分类 创建型模式,共五种: 单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。 结构型模式,共七种: 适配器模式、装饰者模式、代理模式、门面模式(外观模式)、桥梁模式、组合模式、享...
  • 学习6设计原则、23种设计模式

    万次阅读 多人点赞 2018-03-14 17:35:57
    了解设计模式的朋友们,想必都听说过“六设计原则”吧。其实最经典的 23 种设计模式中或多或少地都在使用这些设计原则,也就是说,设计模式是站在设计原则的基础之上的。所以在学习设计模式之前,很有必要对这些...
  • 设计模式之面向对象七基本原则

    万次阅读 2015-04-27 16:25:48
    概述在运用面向对象的思想进行软件设计时,需要遵循的原则一共有7个,他们是:1. 单一职责原则(Single Responsibility Principle)每一个类应该专注于做一件事情。2. 里氏替换原则(Liskov Substitution Principle...
  • 设计模式的三分类及六大原则

    万次阅读 多人点赞 2018-08-20 00:47:11
    总体来说设计模式分为三类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元...
  • android 24种设计模式介绍与6设计原则
  • 设计模式的总结有助于构建软件开发知识体系,为后期软件的架构设计、重构打下夯实基础,所以开设了Android设计模式专栏,... 本文重在总结设计模式和设计原则,后期会结合具体实例代码来说明常用的设计原则设计模式

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 377,585
精华内容 151,034
关键字:

设计模式7大原则