zoukankan      html  css  js  c++  java
  • OOAD之面向对象设计原则

    学习这个设计模式 真的觉得很抽象,只有自己多多的领会!

    在很多时候,很多的知识都会觉得讲起来是很矛盾的。

    本章目标

    1 掌握内聚度和耦合度的概念

    2 掌握面向对象设计原则 

    (一)如何衡量软件设计的质量

    内聚度:表示一个应用程序的单个单元所负责的任务数量和多样性。内聚与单个类或者单个方法单元相关。(在我自己的理解就是:在一个类中完成自己所有的任务,这些任务都在自己的类中。自己的事情自己做)

    耦合度:耦合度表示类之间关系的紧密程度。耦合度决定了变更一个应用程序的容易程度。在紧密耦合的类结构中,更改一个类会导致其它的类也随之需要做出修改。

    设计原则:

    “高内聚 低耦合”是

    在设计时遵循的一定的设计原则:

    设计原则名称

    设计原则简介

    重要性

    单一职责原则

    类的职责要单一,不能将太多的职责放在一个类中。

    ★★★★☆

    开闭原则

    软件实体对扩展是开放的,但对修改是关闭的,即在不修改一个软件实体的基础上去扩展其功能。

    ★★★★★

    里氏替换原则

    在软件系统中,一个可以接受基类对象的地方必然可以接受一个子类对象。

    ★★★★☆

    依赖倒转原则

    要针对抽象层编程,而不要针对具体类编程。

    ★★★★★

    接口隔离原则

    使用多个专门的接口来取代一个统一的接口。

    ★★☆☆☆

    组合/聚合复用原则

    在系统中应该尽量多使用组合和聚合关联关系,尽量少使用甚至不使用继承关系。

    ★★★★☆

    迪米特法则

    一个软件实体对其他实体的引用越少越好,或者说如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用,而是通过引入一个第三者发生间接交互。

    ★★★☆☆

    一: 单一职责原则: 

    Single Responsibility Principle,SRP
    定义:所有的对象都应该有单一的职责,它提供的所有的服务也都仅围绕着这个职责。(对于一个类而言,应该仅有一个引起它变化的原因,永远不要让一个类存在多个改变的理由。)
    对单一职责的理解:
    eg: 在你一个类中,他即存在属性,又存在一些方法,那么他的职责就不是单一的,他既要担任设计属性,又要担任方法的设计。
     所以一般在一个类中,只存在属性的,即使有一些方法 也只是有getter,setter 方法。把方法写在一个接口中。
    单一职责原则的思考:
     1:单一职责原则提出了对对象职责的一种理想期望。
     2:单一职责原则还有利于对象的稳定。
     3:单一职责原则并不是极端地要求我们只能为对象定义一个职责,而是利用极端的表述方式重点强调:在定义对象职责时,必须考虑职责与对象之间的所属关系。(这又有些矛盾了!)
     二:开闭原则  :  开闭原则(Open-Close Principle,简称OCP)是指一个软件实体(类、模块、方法等)应该对扩展开放,对修改关闭
    遵循开闭原则设计出来的模块具有两个基本特征:
    对于扩展是开放的(Open for extension):模块的行为可以扩展,当应用的需求改变时,可以对模块进行扩展,以满足新的需求。
    对于更改是封闭的(Closed for modification):对模块行为扩展时,不必改动模块的源代码或二进制代码。
    如何实现开闭原则?
    关键在于抽象化
    抽象化分为两种情况: 
    针对多个领域类的抽象化:
    一组对象的共同行为抽象到抽象类或者接口中,而将不同行为的实现封装在子类或者实现类中。接口或抽象类是不能实例化的,因此对修改就是关闭的;而添加新功能只要实现接口或者继承抽象类,从而实现对扩展开放
    使用抽象类:在设计类时,对于拥有共同功能的相似类进行抽象化处理,将公用的功能部分放到抽象类中,而将不同的行为封装在子类中。这样,在需要对系统进行功能扩展时,只需要依据抽象类实现新的子类即可。在扩展子类时,不仅可以拥有抽象类的共有属性和共有方法,还可以拥有自定义的属性和方法。
    使用接口:与抽象类不同,接口只定义实现类应该实现的接口方法,而不实现公有的功能。在现在大多数的软件开发中,都会为实现类定义接口,这样在扩展子类时必须实现该接口。如果要改换原有的实现,只需要改换一个实现类即可。
    eg:
    年薪制员工(用Salary类表示)、按小时付费员工(用Hourly类表示)、合同工(用Contractor类表示)共同的行为:计算薪酬  邮寄支票
    建立一个抽象类:employee
      有属性:id,name,address;
      有方法:computePay,mailheck,
    建立三个类:Salary,Hourly,Contractor,继承抽象类employee,拥有自己的属性,计算薪酬的方法。
     
    针对单个领域类的抽象化
    将单个领域类中可能会发生变化的行为进行封装,也就是找出类中可能需要变化之处,把它们封装成抽象类或者接口,从而将变化点与不需要变化的代码分离。

     开闭原则是核心:开闭原则是面向对象设计的核心所在。遵循这个原则可以带来灵活性、可重用性和可维护性。

    其它设计原则(里氏替换原则、依赖倒转原则、组合/聚合复用原则、迪米特法则、接口隔离原则)是实现开闭原则的手段和工具。

    OOAD理论的知识很多,实践的比较少的。理解起来呢 真的比较抽象的,有些时候讲的知识也感觉是矛盾的。

    三:里氏替换原则(The Liskov Substitution Principle,LSP)的定义:在一个软件系统中,子类应该能够完全替换任何父类能够出现的地方,并且经过替换后,不会让调用父类的客户程序从行为上有任何改变。
    里氏替换原则是使代码符合开闭原则的一个重要的保证,同时,它体现了:
    类的继承原则:里氏替换原则常用来检查两个类是否为继承关系。在符合里氏替换原则的继承关系中,使用父类代码的地方,用子类代码替换后,能够正确的执行动作处理。换句话说,如果子类替换了父类后,不能够正确执行动作,那么他们的继承关系就是不正确的,应该重新设计它们之间的关系。
    动作正确性保证:里氏替换原则对子类进行了约束,所以在为已存在的类进行扩展,来创建一个新的子类时,符合里氏替换原则的扩展不会给已有的系统引入新的错误。
    eg:正方形不是长方形
     
     1 package com.lovo.chap2;
     2 /**
     3  * 长方形 父类
     4  * @author acer
     5  *
     6  */
     7 public class Rectangle {
     8     private int width;
     9     private int height;
    10     
    11     public int getWidth() {
    12         return width;
    13     }
    14     public void setWidth(int width) {
    15         this.width = width;
    16     }
    17     public int getHeight() {
    18         return height;
    19     }
    20     public void setHeight(int height) {
    21         this.height = height;
    22     }
    23     
    24 
    25 }
     1 package com.lovo.chap2;
     2 /**
     3  * 正方形继承长方形
     4  * @author acer
     5  *
     6  */
     7 public class Square extends Rectangle  {
     8     @Override
     9     public void setHeight(int height) {
    10         super.setHeight(height);
    11         super.setWidth(height);
    12     }
    13 
    14 }
     1 package com.lovo.chap2;
     2 
     3 public class test {
     4     public void design(Rectangle rc){
     5         while(rc.getHeight()<=rc.getWidth()){//这里为什么还要用等于呢
     6             System.out.println(rc.getHeight());
     7             rc.setHeight(rc.getHeight()+1);
     8             
     9         }
    10 
    11     }
    12     public static void main(String[] args) {
    13         test t=new test();
    14         Rectangle re=new Rectangle();
    15         re.setHeight(50);
    16         re.setWidth(100);
    17         t.design(re);
    18          
    19         Square s=new Square();
    20         s.setHeight(200);
    21         t.design(s);
    22         
    23     }
    24 
    25 }
    里氏代换原则给我们的启示:
    类的继承原则:如果一个继承类的对象可能会在基类出现的地方出现运行错误,则该子类不应该从该基类继承,或者说,应该重新设计它们之间的关系。
    动作正确性保证:符合里氏代换原则的类扩展不会给已有的系统引入新的错误。 
    四:依赖倒转原则
    依赖倒转原则(Dependency Inversion Principle,简称DIP)是指将两个模块之间的依赖关系倒置为依赖抽象类或接口。
    具体有两层含义:
    1 高层模块(是指调用的类)不应该依赖于低层模块(是指被调用的类),二者都应该依赖于抽象;
    2 抽象不应该依赖于细节,细节应该依赖于抽象。
    eg:
    人可以通过看书 看报 看网页来学习
     
    1 package com.lovo.dip;
    2 
    3 public interface Study {
    4     public void read();
    5 
    6 }
     1 package com.lovo.dip;
     2 /**
     3  * 读书
     4  * @author acer
     5  *
     6  */
     7 public class ReadBooks implements Study {
     8 
     9     @Override
    10     public void read() {
    11     System.out.println("读书学习");
    12     }
    13 
    14 }
     1 package com.lovo.dip;
     2 /**
     3  * 报纸
     4  * @author acer
     5  *
     6  */
     7 public class ReadPaper implements Study {
     8 
     9     @Override
    10     public void read() {
    11       System.out.println("读报纸学习");
    12     }
    13 
    14 }
     1 package com.lovo.dip;
     2 /**
     3  * 网页
     4  * @author acer
     5  *
     6  */
     7 public class Online implements Study {
     8 
     9     @Override
    10     public void read() {
    11      System.out.println("网页学习!");
    12     }
    13 
    14 }
    1 package com.lovo.dip;
    2 
    3 public class StudyMethods {
    4 
    5     public void read(Study s) {
    6        s.read();
    7     }
    8 
    9 }
     1 package com.lovo.dip;
     2 /**
     3  * 
     4  * dip 依赖倒转原则 
     5  * @author acer
     6  *
     7  */
     8 public class Test {
     9 
    10     public static void main(String[] args) {
    11         StudyMethods st=new StudyMethods();
    12         st.read(new ReadPaper());
    13         //st.read(new ReadBooks());
    14         //st.read(new Online());
    15 
    16 
    17     }
    18 
    19 }
    依赖倒转原则给我们的启示:要针对接口编程,不要针对实现编程。(Program to an interface. not an implementation)
    五:组合/聚合复用原则
    组合/聚合复用原则(Composite/Aggregation Reuse Principle,CARP)是指要尽量使用组合/聚合而非继承来达到复用目的。另一种解释是在一个新的对象中使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象委托功能达到复用这些对象的目的。 
    六:接口隔离原则
    接口隔离原则(Interface Segregation Principle,简称ISP)是指客户不应该依赖它们用不到的方法,只给每个客户它所需要的接口。
    接口隔离原则两层意思(1):
    接口的设计原则:接口的设计应该遵循最小接口原则,不要把用户不使用的方法塞进同一个接口里。如果一个接口的方法没有被使用到,则说明该接口过胖,应该将其分割成几个功能专一的接口,使用多个专门的接口比使用单一的总接口要好。
    比如:a 要使用b接口中的test1,test2方法,但是在b接口中有test1,test2,test3,test4方法,那么最好就是把test1,test2 方法分出来 放在另一个接口中。
    接口隔离原则两层意思(2):
    接口的继承原则:如果一个接口A继承另一个接口B,则接口A相当于继承了接口B的方法,那么继承了接口B后的接口A也应该遵循上述原则:不应该包含用户不使用的方法。反之,则说明接口A被B给污染了,应该重新设计它们的关系。
    七:迪米特法则
    迪米特法则(Law of Demeter,简称LOD),又称为“最少知识原则”,它的定义为:一个软件实体应当尽可能少的与其他实体发生相互作用。
    迪米特法则的初衷在于降低类之间的耦合。由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。
    最经典的例子就是:不要和陌生人说话。
     迪米特法则的核心观念就是类间解耦,弱耦合,只有弱耦合了以后,类的复用率才可以提高。
     
  • 相关阅读:
    2.12 使用@DataProvider
    2.11 webdriver中使用 FileUtils ()
    Xcode8 添加PCH文件
    The app icon set "AppIcon" has an unassigned child告警
    Launch Image
    iOS App图标和启动画面尺寸
    iPhone屏幕尺寸、分辨率及适配
    Xcode下载失败 使用已购项目页面再试一次
    could not find developer disk image
    NSDate与 NSString 、long long类型的相互转化
  • 原文地址:https://www.cnblogs.com/hellokitty1/p/4629108.html
Copyright © 2011-2022 走看看