zoukankan      html  css  js  c++  java
  • 软件设计的七大原则

    https://blog.csdn.net/weixin_44036154/article/details/109026656

    目录:

    1、开闭原则

    2、里氏替换

    3、依赖倒置

      在软件开发中,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序员要尽量根据 7 条原则来开发程序,从而提高软件开发效率、节约软件开发成本和维护成本。

      这 7 种设计原则是软件设计模式必须尽量遵循的原则,各种原则要求的侧重点不同。其中,开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合度;合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。

    1、开闭原则

    (1)原则定义:

    软件实体应当对扩展开放,对修改关闭,这就是开闭原则的经典定义。

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

    • 项目中划分出的模块
    • 类与接口
    • 方法
    开闭原则的含义是:当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求。

    (2)实现原理:

       可以通过“抽象约束、封装变化”来实现开闭原则,即通过接口或者抽象类为软件实体定义一个相对稳定的抽象层,而将相同的可变因素封装在相同的具体实现类中。
      因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要发生变化时,只需要根据需求重新派生一个实现类来扩展就可以了。
     

    (3)实例展示:

    /**
     * 定义课程接口
     */
    public interface ICourse {
        String getName(); // 获取课程名称
        Double getPrice(); // 获取课程价格
        Integer getType(); // 获取课程类型
    }
    
    /**
     * 英语课程接口实现
     */
    public class EnglishCourse implements ICourse {
        private String name;
        private Double price;
        private Integer type;
    //省略get,set,空参,满参
    }
    
    // 测试
    public class Main {
        public static void main(String[] args) {
            ICourse course = new EnglishCourse("小学英语", 199D, "Mr.Zhang");
            System.out.println(
                    "课程名字:" + course.getName() + " " +
                            "课程价格:" + course.getPrice() + " " +
                            "课程作者:" + course.getAuthor()
            );
        }
    }

    项目上线,但是出现了节假日打折的情况出现,现在有以下这几种方法去修改:

    1:修改接口(不可取,修改接口时其他的代码也得改!)

    2:修改实现类(不可取,这样会有两个获取价格的方法!)

    3:扩展实现方法(可取,不改变原有代码,功能可实现!)

    直接添加一个子类 SaleEnglishCourse ,重写 getPrice()方法,这个方案对源代码没有影响,符合开闭原则,所以是可执行的方案

    public class SaleEnglishCourse extends EnglishCourse {
        public SaleEnglishCourse(String name, Double price, String author) {
            super(name, price, author);
        }
        @Override
        public Double getPrice() {
            return super.getPrice() * 0.85;
        }
    }

    (4)开闭原则的作用

    开闭原则是面向对象程序设计的终极目标,它使软件实体拥有一定的适应性和灵活性的同时具备稳定性和延续性。具体来说,其作用如下。

    1. 对软件测试的影响

    软件遵守开闭原则的话,软件测试时只需要对扩展的代码进行测试就可以了,因为原有的测试代码仍然能够正常运行。

    2. 可以提高代码的可复用性

    粒度越小,被复用的可能性就越大;在面向对象的程序设计中,根据原子和抽象编程可以提高代码的可复用性。

    3. 可以提高软件的可维护性

    遵守开闭原则的软件,其稳定性高和延续性强,从而易于扩展和维护。

     

     2、里氏替换原则

    (1)原则定义

    继承必须确保超类(被继承的类称为超类,继承的类称为子类)所拥有的性质在子类中仍然成立。

    里氏替换原则主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中蕴含的原理。里氏替换原是继承复用的基础,它反映了基类与子类之间的关系,是对开闭原则的补充,是对实现抽象化的具体步骤的规范。

    (2)实现原理:

    1、子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法

    2、子类可以有自己的个性
    3、覆盖或实现父类的方法时输入参数可以被放大

    4、覆写或实现父类的方法时输出结果可以被缩小

    (3)实例展示:

    1、子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法

    子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法,父类中凡是已经实现好的方法(相对于抽象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。
    (略)

    2、子类可以有自己的个性

    在继承父类属性和方法的同时,每个子类也都可以有自己的个性,在父类的基础上扩展自己的功能。前面其实已经提到,当功能扩展时,子类尽量不要重写父类的方法,而是另写一个方法,所以对上面的代码加以更改,使其符合里氏替换原则。

    (略)

    3、覆盖或实现父类的方法时输入参数可以被放大

    当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。

    String 继承于CharSequence)
    public class ParentClazz {
        public void say(String str) {
            System.out.println("parent execute say " + str);
        }
    }
    
    public class ChildClazz extends ParentClazz {
        public void say(CharSequence str) {
            System.out.println("child execute say " + str);
        }
    }
    
    // 执行结果:
    // parent execute say hello
    // parent execute say hello
    // 参数大小不一样,一直用的都是string,父类的

    4、覆写或实现父类的方法时输出结果可以被缩小

    当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

    public abstract class Father {
        public abstract Map hello();
    }
    
    
    public class Son extends Father {
        @Override
        public Map hello() {
            HashMap map = new HashMap();
            System.out.println("son execute");
            return map;
        }
    }

    (4)里氏替换的作用:

    里氏替换原则是实现开闭原则的重要方式之一。

    它克服了继承中重写父类造成的可复用性变差的缺点。
    它是动作正确性的保证。即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。

     3、依赖倒置原则

    (1)原则定义:

    依赖倒置原则的原始定义为:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程。

    依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。
    由于在软件设计中,细节具有多变性,而抽象层则相对稳定,因此以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定得多。这里的抽象指的是接口或者抽象类,而细节是指具体的实现类。
    使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给它们的实现类去完成。

    (2)实现原理

    依赖倒置原则的目的是通过要面向接口的编程来降低类间的耦合性,所以我们在实际编程中只要遵循以下4点,就能在项目中满足这个规则。

    每个类尽量提供接口或抽象类,或者两者都具备。
    1. 变量的声明类型尽量是接口或者是抽象类。
    2. 任何类都不应该从具体类派生。
    3. 使用继承时尽量遵循里氏替换原则。

    (3)实例展示

    public class T2 {
        public static void main(String[] args) {
            IDriver zhangsan = new Driver();
            Icar benz = new Benz();
            zhangsan.drive(benz);
            Icar bmw = new BMW();
            zhangsan.drive(bmw);
        }
    }
    
    interface IDriver {
        // 司机职责就是驾驶汽车
        public void drive(Icar car);
    }
    
    class Driver implements IDriver {
        // 司机职责就是驾驶汽车
        @Override
        public void drive(Icar car) {
            car.run();
        }
    }
    
    interface Icar {
        // 车的作用就是跑
        public void run();
    }
    
    class Benz implements Icar {
        // 车的作用就是跑
        @Override
        public void run() {
            System.out.println("奔驰车跑起来了");
        }
    }
    
    
    class BMW implements Icar {
        // 车的作用就是跑
        @Override
        public void run() {
            System.out.println("宝马车跑起来了");
        }
    }
    (4)依赖倒置原则作用:

    依赖倒置原则的主要作用如下。

    依赖倒置原则可以降低类间的耦合性。
    1. 依赖倒置原则可以提高系统的稳定性。
    2. 依赖倒置原则可以减少并行开发引起的风险。
    3. 依赖倒置原则可以提高代码的可读性和可维护性。
  • 相关阅读:
    VIJOS-P1340 拯救ice-cream(广搜+优先级队列)
    uva 11754 Code Feat
    uva11426 GCD Extreme(II)
    uvalive 4119 Always an Interger
    POJ 1442 Black Box 优先队列
    2014上海网络赛 HDU 5053 the Sum of Cube
    uvalive 4795 Paperweight
    uvalive 4589 Asteroids
    uvalive 4973 Ardenia
    DP——数字游戏
  • 原文地址:https://www.cnblogs.com/guoyu1/p/13976392.html
Copyright © 2011-2022 走看看