• 软件体系结构——第七章<面向对象的设计原则>


    一、设计需要原则

    面向对象的设计原则是构造高质量软件的出发点

    什么是好的设计?

    • 容易理解

    • 容易修改和扩展

    • 容易复用

    • 容易实现与应用

    • 简单、紧凑、经济适用

    • 让人工作起来心情愉快的设计

    面向对象的基本设计原则(模式):

    • LSP:Liskov替换原则 The Liskov Substitution Principle

    • OCP:开放-封闭原则 The Open-Close Principle

    • SRP:单一职责原则 The Single Responsibility Principle

    • ISP:接口隔离原则 The Interface Segregation Principle

    • DIP:依赖倒置原则 The Dependency Inversion Principle

    二、LSP-Liskov替换原则

    LSP(The Liskov Substitution Principle)

    定义:“若对于类S的任一对象o1,均有类T的对象o2存在,使得在类T定义的所有程序P中,用o1替换o2之后,程序的行为不变,则类S是类T的子类”,即“子类对象必须可以替换父类对象”

    违背LSP原则的范例——

    image.png

    怎么解决此问题?——使用抽象

    image.png

    抽象类与具体类的区别:

    image.png

    正确方案:

    image.png

    三、OCP-开放-封闭原则

    lOCP(The Open-Close Principle)的定义

    • 对任何一个事物来说,“变化是永恒的主题,不变是相对的定义”,由此,可得出软件实体(类、模块、函数等)应该是可扩展的,但是不可修改的——功能不变性

    OCP原则的特征:

    • 对于扩展是开放的(Open for extension):模块的行为可以扩展,当应用的需求改变时,可以对模块进行扩展,以满足新的需求

    • 对于更改是封闭的(Closed for modification):对模块行为扩展时,不需改动模块源代码即可满足新需求

    OCP的关键在于扩展抽象的利用:

    • 抽象技术:abstract class、Interface

    • 抽象内容预见了可能的所有扩展(闭)

    • 由抽象可以随时导出新的类(开)

    实例:手与门

    手与门的行为表现为:

    • 开门(open)

    • 关门(close)

    • 判断门的状态(isOpened)

    image.png

    public class Door {
        private boolean _isOpen=false;
        public boolean isOpen(){
            return _isOpen;
        }
        public void open(){
            _isOpen = true;
        }
        public void close(){
            _isOpen = false;
        }
    }
    
    public class Hand {
        public Door door;
        void do() {
            if (door.isOpen())
                 door.close();
            else
                door.open();
        }
    }
    
    //Test
    public class SmartTest {
        public static void main(String[] args) {
            Hand myHand = new Hand();
            myHand.door = new Door();
            myHand.do();
        }
    }
    

    新的需求出现后如何应对?如:用手开关抽屉

    image.png

    public class Hand {
        public Door door;
        public Drawer drawer;
        void do(int item) {
            switch (item){
                case 1:  //开门程序
                    if (door.isOpen())
                         door.close();
                    else   door.open();
                    break;
    	case 2: //开抽屉程序
     	    if (drawer.isOpen())
                          drawer.close();
                     else  drawer.open();
               break; 
            }
        }
    }
    
    //Test
    public class SmartTest {
        public static void main(String[] args) {
            Hand myHand = new Hand();
            myHand.door = new Door();        
            myHand.drawer = new Drawer();
            myHand.do(1);   //手开门
        }
    }
    

    发现,这样改动非常麻烦!

    我们设计出符合OCP的设计方案:

    image.png

    public interface Excutable {
        public boolean isOpen();
        public void open();
        public void close();
    }
    
    public class Hand {
        public Excutable item;
        void do() {
            if (item.isOpen())
                item.close();
            else
                item.open();
        }
    }
    
    public class Door implements Excutable {
        private boolean _isOpen = false;
        public boolean isOpen() {
            return _isOpen;
        }
        public void open() {
            _isOpen = true;
        }
        public void close() {
            _isOpen = false;
        }
    }
    
    public class Drawer implements Excutable {
        private boolean _isOpen = false;
        public boolean isOpen() {
            return _isOpen;
        }
        public void open() {
            _isOpen = true;
        }
        public void close() {
            _isOpen = false;
        }
    }
    
    //add a refrigerator
    public class Refrigerator implements Excutable {
        private boolean _isOpen = false;
        public boolean isOpen() {
            return _isOpen;
        }
        public void open() {
            _isOpen = true;
        }
        public void close() {
            _isOpen = false;
        }
    }
    
    //Test
    public class SmartTest {
        public static void main(String[] args) {
            Hand myHand = new Hand();
            myHand.item = new Door();
            myHand.do();
        }
    }
    

    通过扩展应对新需求,不需要修改任何原有的设计和代码~

    OCP的优势:

    • 可以极大提高软件的设计质量,耦合度低、易扩展、易修改

    • 当预测到可能的变化时,通过抽象类(接口)来隔离它。

    • 关键技术是“扩展抽象”原则的利用。

    • 成功的预测将极大提高软件的生存力,而失败的预测,将带来“不必要的复杂性”的设计“臭味”

    四、SRP-单一职责原则

    作为面向对象系统最基本的元素,类自身的设计质量将直接影响到整个设计方案的质量。因此,对于单个类而言,最核心的工作就是类的职责分配过程——职责单一。

    SRP(The Single Responsibility Principle)定义:就一个类而言,应该仅有一个引起它变化的原因,即内聚性——一个类只完成一个功能

    违反SRP的案例:

    image.png

    解决方案:

    image.png

    SRP是一个非常简单的原则,但却是最难正确应用的原则之一——类职责的高内聚

    • 如模块独立性原则“高内聚、低耦合”,知道该原则是追求的设计目标,但难以描述怎样才能达到高内聚的目标

    SRP明确告诉设计人员必须保持类职责的内聚性

    • 主要做法:结合业务场景考虑职责的相关性,与系统的耦合程度密切关联起来

    五、ISP-接口隔离原则

    ISP(The Interface Segregation Principle)定义

    • 客户不应该依赖他们用不到的方法,只给每个客户提供所需的接口——角色

    • 为了避免“肥接口(没有关系的接口合并在一起)(fat interface)”,应当以一个类实现多个专用的接口,而各客户仅仅获知必须的接口

    优势:

    • 为不同角色提供宽窄不一的接口,以对付不同的客户端或使用者(都是业务参与者);

    • 接口的职责明确,有利于系统的维护,同时,有利于降低设计成本;

    • 平常设计时总是向客户端和使用者提供public接口是一种承诺,应尽量减少这种承诺;

    • 接口污染:为节省接口的数目,将类似的接口合并,使得接口变得臃肿,造成接口污染。

    接口污染案例:

    image.png

    解决方案:

    • 使用委托分离接口: 适配器(Adapter)模式

    • 使用多重继承(实现)分离接口

    image.png

    六、DIP-依赖倒置原则

    传统的层次结构:

    image.png

    DIP特性:

    • 高层模块不依赖于低层模块,二者都依赖于抽象(需要定义中间抽象层)

    • 抽象不依赖于细节,细节依赖于抽象

    • 针对接口编程,不要针对实现(细节)编程

    符合DIP的系统:

    image.png

    启发式原则:

    • “依赖于抽象”—程序中所有依赖关系都应该终止于抽象类或者接口

    • 启发式原则——要符合LSP原则

      • 任何类都不应该从具体类派生(始于抽象、来自具体)
      • 任何方法都不应该改写其任何基类中已经实现的方法(除非有特殊的需求)
    • UML中箭头的方向就代表了依赖的方向

    本质:

    • 通过抽象提取业务本质,并建立一个稳定的静态结构(抽象类图)描述这个业务本质

    • 对于具体的业务规则的处理是在这个业务本质的基础上的扩展

    • 注意:技术、工具、意识形态等的发展可能使业务规则不断变化,但业务的本质不变;因此,DIP原则可帮助设计人员轻松的适应这些变更

  • 相关阅读:
    json解析与序列化
    js实现千位分隔符
    map.(parseInt)方法详解
    js实现翻转一个字符串
    一个满屏 品 字布局 如何设计?
    new操作符实现过程
    常见的函数式编程模型
    Azure DevOps Server 2019 (TFS)安装教程
    在Azure DevOps Server (TFS) 中修改团队项目名称
    你好,Azure DevOps Server 2019;再见,Team Foundation Server
  • 原文地址:https://www.cnblogs.com/wangzheming35/p/16219361.html
Copyright © 2020-2023  润新知