继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

软件设计七大原则

慕姐8265434
关注TA
已关注
手记 1147
粉丝 221
获赞 1064

1、开闭原则

  • 开闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

  • 用抽象构建框架,用实现扩展细节。

  • 优点: 提高软件系统的可复用性及可维护性。

不要改你以前写的代码,你应该加一些代码去扩展原来的功能,来实现新的需求。好处很好理解,改原来的代码很容易影响原来的功能,特别是接手别人的代码,不理解原先业务场景的情况下。

新添加校验规则的话,尽量不要修改以前的校验规则。可以回引入新的风险。

具体代码实现:

webp

image

举例: 比如有一个课程抽象类,该课程包含课程id,名称,价格。同时开放的课程有java课程,C语言课程。上面的UML图就是两者之间的关系。

如果在此基础上需要添加优惠课程。那么我们有两种实现方式。一种就是直接在抽象接口中声明一个优惠获得价格的方法。另一种就是在java课程中直接修改获取价格的方法。

但是这两种方式都会存在问题。前者的问题在于修改的地方太多,接口是不应该经常变化的,尤其是在有很多实现类的前提下,这样修改会让我们修改很多实现类。后者的问题在于我们就无法获取原来的价格。不符合需求。

那么究竟怎样是合理的呢?

如果只是java课程打折,那么我们最好使用继承的方式,对原来的java课程进行扩展。

webp

image

尽量不对底层的方法进行修改,防止风险的扩散。越高层的影响越小,提高了复用性。

2、依赖倒置原则

  • 定义:高层模块不应该依赖底层模块,两者都应该依赖其抽象。

  • 抽象不应该依赖细节;细节应该依赖抽象。

  • 针对接口编程,不要针对实现编程。

  • 优点: 可以减少类间的耦合性,提高系统稳定性,提高代码可读性和可维护性,可降低修改程序造成的风险。

webp

image

上图是典型的面向实现编程,一旦我们需要添加新的课程就需要修改该类,改动是很频繁的。这里我们引入抽象。然后实现接口的方式。在应用层通过参数注入的方式调用具体实现类。

webp

image

当然这样会有一个问题,我们在Mical类中只能注入一次ICourse的实例。那么为了多次调用,需要将ICourse暴露出去。

webp

image

3、单一职责原则

  • 单一职责原则:不要存在多于一个导致类变更的原因。

  • 一个类、接口、方法只负责一项职责。

  • 优点: 降低类的负责度,提高类的可读性,提高系统的可维护性,降低变更引起的风险。

例如声明一个鸟类,方法为行动的方式

public class Bird {

    public void mainMoveMode(String birdName) {
        System.out.println(birdName+ "用翅膀飞");
    }
}

在实际调用时,属于鸟类的有大雁,企鹅,鸵鸟。那么其实企鹅和鸵鸟其实不是使用翅膀的,这就出现了需求不一致的问题。我们一般的做法就是根据传入的参数判断,然后输出不同的结果。

public class Bird {

    public void mainMoveMode(String birdName) {        if (birdName.equals("鸵鸟")){
            System.out.println(birdName + "用脚走");
        }else {
            System.out.println(birdName + "用翅膀飞");
        }
    }
}

这样会更改实现的具体流程,不留神就改错了。尤其是对于边界条件比较复杂的处理流程而言。

webp

image

再比如课程类

public interface Course {    //获取课程信息
    String getCourseName();    byte[] getCourseVideo();    
    //课程管理
    void studyCourse();    void refundCourse();
}

在这个类中,我们可以看到获取课程信息和退单是相互影响的。

那么我们可以将其进行拆分。

webp

image

4、接口隔离原则

  • 用多个专门的接口,而不是单一的总接口,客户端不应该依赖它不需要的接口。

  • 一个类对一个类的依赖应该建立在最小的接口上。

  • 建立单一的接口,不要建立庞大臃肿的接口。

  • 尽量细化接口,接口中的方法尽量少。

  • 优点: 符合我们常说的高内聚低耦合的设计思想,从而使得类具有很好的可读性,可扩展性和可维护性。

    webp

    image

比如狗是不会飞的,那么我们要实现这个接口,就必须将它的fly方法不予实现。造成了浪费。
我们可以适度的将接口拆分,但不可过于细

webp

image

5、迪米特法则

  • 一个对象应该对其他对象保持最少的了解。又叫做最少知道原则。

  • 尽量降低类与类之间的耦合。

  • 强调只和朋友交流,不和陌生人说话。

  • 朋友: 出现在成员变量,方法的输入,输入参数重的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。

  • 优点: 降低类之间的耦合。

防疫站需要每个宠物的信息,这时候需要一个EpidemicStation对象。如何获取宠物信息有2种方式
通过宠物的主人,EpidemicStation早已有了Host对象,而Host中有一系列关于宠物(Animal)的方法
直接new一个宠物的对象,获取相关信息。

我们肯定直接会选择第一种。。。直觉是可以少建个对象。。。早说了我就是这种偷懒的程序猿。。。然而莫名的契合了迪米特法则。

Host只需要对Animal对象保持关注,而EpidemicStation只需要对Host对象保持关注。EpidemicStation对象不需要了解Animal。感觉直接点就是,在一个类中应该少出现其他类,其实这也是解耦的需要。

6、里氏替换原则

  • 该原则是在1988年,由麻省理工学院的以为姓里的女士提出的。

  • 如果对每个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。

换句话说,所有引用基类的地方必须能透明地使用其子类的对象。

由定义可知,在使用继承时,遵循里氏替换原则,在子类中尽量不要重写和重载父类的方法。

继承包含这样一层含义:父类中凡是已经实现好的方法(相对抽象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵循这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。

继承作为面向对象三大特性之一,在给程序设计带来巨大遍历的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障。

public interface ICourse {    Integer getId();    String getName();    Double getPrice();
}
public class JavaCourse implements ICourse {    private   Integer id;    private String name;    private  Double price;    public JavaCourse( Integer id,String name, Double price) {        this.id = id;        this.name = name;        this.price  = price;
    }    @Override
    public Integer getId() {        return this.id;
    }    @Override
    public String getName() {        return this.name;
    }    @Override
    public Double getPrice() {        return this.price;
    }    @Override
    public String toString() {        return "JavaCourse{" +                "id=" + id +                ", name='" + name + '\'' +                ", price=" + price +                '}';
    }
}
public class JavaDiscountCourse extends JavaCourse {    public JavaDiscountCourse(Integer id, String name, Double price) {        super(id, name, price);
    }    public Double getDisCountPrice(){        return  super.getPrice()* 0.8;
    }    @Override
    public Double getPrice() {        return super.getPrice() ;
    }
}
public static void main(String[] args) {

        ICourse javaCourse = new JavaDiscountCourse(95,"Java架构设计",128.0);
        System.out.println(                "课程Id:"+javaCourse.getId()
                + "课程名称:"+ javaCourse.getName()
                + "课程原格:"+ javaCourse.getPrice()
                + "课程优惠价格:"+ ((JavaDiscountCourse) javaCourse).getDisCountPrice()
        );
    }



作者:AKyS佐毅
链接:https://www.jianshu.com/p/c460295f9964


打开App,阅读手记
2人推荐
发表评论
随时随地看视频慕课网APP