前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >简述面向对象六大设计原则

简述面向对象六大设计原则

作者头像
open
发布2020-03-19 17:11:33
5270
发布2020-03-19 17:11:33
举报

前言

本篇文章通过概念、实例分析,解读面向对象六大设计原则,希望能对你有所帮助。

一、单一职责原则

  • 定义:就一个类而言,应该仅有一个引起它变化的原因。
  • 理解:当一个类所负责的事情足够单一的时候,不仅可以能够专注的把所负责事情做好。如果一个类负责多个职责,必然会导致各个职责相互之前存在耦合。这就不符合我们高内聚、低耦合的要求。导致的问题就是,这个类的代码在不断的增加,牵着着各种功能点的代码。如果某个功能需要修改时,不得不考虑是否对其他的功能带来影响。

二、开闭原则

  • 定义:对于扩展是开放的,对于修改是封闭的;
  • 理解:意思就是可以任意的往外边扩展,但是不能对写好的代码修改,怎么达到这个要求呢?写接口。执行的方法写成接口,这样如果我们要扩展不同的实现,那就可以扩展新的实现了原来接口的类,然后丢进去就可以啦;
  • 实例:
    //执行体
    class A {
        // H:相当于任务的执行者
        private void doA( H h){
            h.doMyTask();//此处调用接口的方法,达到 闭 的效果,只管我要干啥,具体怎么干可以不管
        }
    }
    ---------------------------
    // 接口
    interface H{
        void doMyTask();
    }
    ---------------------------
    //任务执行者实现体
    class B implements H{
        void doMyTask(){
            sys.out("干B的活");
        }
    }

    class C implements H{
         void doMyTask(){
             sys.out("干C的活");
         }
    }

    //操作者
    class K {
        A a =new A();
        a.doA(new B);
        a.doA(new C);
        a.doA(new H(){
            doMyTask(){
                 sys.out("干随时扩展自定义的活");
            }
        });

    }
  • 实例分析: 由上述我们可以分析得出,如果我是老K,我现在要让A干一件活,现在我知道要他干什么活,可以写死在A的doA()方法里边,但是如果有一天这个活有了不同的要求,那么我同样还是找A来干活,但是干什么活,通过接口的不同实现来定义;

三、里氏替换原则 LSP

  • 定义:所有应用其基类的地方,必须都能透明的使用其子类的对象;
  • 核心原理:抽象、继承、多态
  • 理解:当我要一个人干一种活的时候,发现有一类人都要干这种活,比如吃饭。那么,我就可以把这一类人抽象出来,同样干“吃饭”这种活,不过很明显,每个人都会有每个人的吃放。所以吃饭这个活也是抽象的,继承的实现体具体去干自己的活。当然,加入我是食堂的,我喊一声可以吃放了。然后不同的人(实现体)就跑进食堂,纷纷吃自己的饭啦!
  • 实例:
       //食堂
       class ShiTang{
            void ganHuo(Person p){
                p.chiFan();
            }
       }
       //抽象
       abstarct class Person{
            public abstarct foid chiFan();
            public void shuiJiao(){
                //do ....
            }
       }
       //小明
       class xiaoMing extends Person{
            public void chiFan(){
                 sys.out("小明吃饭");
            }
       }
       //小兵
       class xiaoBing extends Person{
            public void chiFan(){
                 sys.out("小兵吃饭");
            }
       }
  • 分析:由Person类可以知道,我们把一类人抽象到父类,若果某一件活,不同子类有不同的干法,就发方法抽象出来,子类继承再具体实现它。真正要这一类人干活的时候,直接调父类。这样,如果传入的是子类,也同样适用,并且还能实现各干各的活;

四、依赖倒置原则 DIP

  • 定义:模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或者抽象类产生的;
  • 理解:假如我现在需要租个房子,然后我把身边的朋友叫过来,说给我帮忙找个房子。然后朋友们就去找了。还有一种方案,我可以打个电话给中介,让中介给我找。这样的优势就是,我和真正去找房子的人没有直接的联系。如果朋友临时有事,可能就不能帮忙给我找了。但是,中介就不会发生这种情况;所以,当我们要做一件事的时候,并不需要把做事的人拉进来,而只需要下订单,把事情外包给专门做这种事情的人去做,具体是谁就不要管那么多;这样,可以随时更换外包公司,而不影响自身业务;
  • 实例: //我 class Me{ Zu zu ; // 我找个中介 void setZu(Zu zu){ this.zu=zu; } void zuFangZi(){ zu.zuFang();//我找中介给我租房子 } } //租房这件事 interface Zu{ void zuFang(); } //中介 专干租房的事 class ZhongJie implements Zu{ void zuFang(){ sys.out("中介租房"); } }
  • 分析:有上述示例可以发现,我 和 中介 没有了直接的关联,但是照样把事情干了。如果这个中介倒闭了,我只要去换一家同样能帮我租房子的中介set进来就可以啦!

五、接口隔离原则

  • 定义:客户端不应该依赖它不需要的接口,也可以说是类间的依赖要建立在最小的接口的基础上进行。
  • 理解:小明是人类中的一个实例对象,他有工作挣钱的能力,也有消费付款的能力。那么,对于他供职的公司来说,只需要依赖他工作的能力。对于商场的店主来说,当他消费的时候,就只需要依赖他付款的能力。小明这两项能力,分别对外提供两个接口。那么,公司来说,就看不到付款的接口。对于店主来说,就看不到他工作的接口。如果,哪天小明换了个工作。付款这个接口是没啥影响的。同样的,小明换了一家店消费。对于他供职的公司来说,也没任何影响。就这样,两个接口完美的隔离开。
  • 实例: // 小明这个类 class XiaoMing implements Work,Pay{ public void doWork(){ work;// 努力工作,努力挣钱 } public void pay(){ pay;//消费一把,钱是拿来享受生活的 } } // 对外工作的接口 interface Work{ Money doWork(); } // 对外支付的接口 interface Pay{ void pay(Money money); } // 小明的公司 class Company{ private Work work;//员工1 void run(){ work.doWork(); } } // 小明的去消费的一家商店 class Shop{ private Pay pay;//消费者客户1 void run(){ pay.doPay(); } }
  • 分析:通过上述就可以发现,我们的 Company 只依赖了 XiaoMing 实现的接口 Work,没有依赖其他的接口。这样,XiaoMing 除了 Work 这个以外的接口怎么变都不会影响到 Company,这样子Company 和 Shop 只依赖了各自需要的接口,通过拆分了接口,起到了隔离的作用。

六、迪米特原则

  • 定义:也称最少知道原则,即一个对象应该对其他对象有最少的了解。
  • 理解:其实就是一个类尽最大努力减少对其他类的耦合,同时依赖了一个类也应该将一些方法最少的公开。知道的越少,相互之间的关心的就越少,耦合也就越小。如果有一天,一个类要修改,那么考虑之间的牵连就越少,扩展越容易。
  • 扩展:这里说说怎么执行,我觉得其实很简单,如下:
    • 尽最大的努力隐藏自己。对于Java来说,就是class、方法、变量的描述符,优先级依次从 private 、缺省、protect 、public 的顺序来,能隐藏的绝对不暴露。尤其强调用好包内class的缺省描述,因为实际上而言。既然是已经分了一个包了,那么这个包内有相同的业务职责,理想化的结果就是一个包只有一个对外的public的接口类,而其余都隐藏。
    • 尽最大的努力不依赖别人。这里很好看,对于Java来说,看看自己的class类的import,如果有一大堆的import,尤其看着和自己业务属性无关的import,那么是得考虑进行重构了。

参考资料:《Android源码设计模式解析与实战》

后记

怎么写出优雅的代码?看了一些开源库比如OkHttp、Retrofit等,真的很佩服里面的设计之精巧,对于设计模式的应用恰到好处。然而在项目中,我们在业务开发的时候很少会有这样的代码。因为,大部分而言对于讲究快的移动开发来说,代码的设计精巧已经不是那么的合适了。不是不重要,而是需要平衡投入和产出。所以,本篇追本溯源,聊聊面向对象的设计原则。设计模式只是在此基础上提炼的基本套路,可能生帮硬套会有点麻烦,但是如果在平时的开发过程中小到业务需求的开发,大到项目的架构,以此为准则,一定会有很好的改观。

小贴士

本文由原作者井方哥独家授权Open软件开发小组发布,著作权归原作者所有。如需转载请联系原作者申请授权。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Open软件开发小组 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、单一职责原则
  • 二、开闭原则
  • 三、里氏替换原则 LSP
  • 四、依赖倒置原则 DIP
  • 五、接口隔离原则
  • 六、迪米特原则
    • 参考资料:《Android源码设计模式解析与实战》
      • 后记
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档