设计模式之禅之设计原则概念总结

设计原则概念总结


阅读了设计模式之禅,将设计原则做个概念总结吧,如果想要更好的了解,还是要去看具体细节,这边只能粗略的总结一下,作为一个学习的笔记吧。


单一职责原则

英文名:Single Responsibility Principle 简称SRP

英文定义:

There should never be more than one reason for a class to change

中文翻译:应该有且仅有一个原因引起类的变更.

优点:

  • 1.类的复杂性降低,实现什么职责都有清晰明确的定义;
  • 2.可读性提高(复杂性降低,可读性自然就提高了);
  • 3.可维护性提高(可读性提高,可维护性自然就更容易了);
  • 4.变更引起的风险降低

总结:对于单一职责原则,接口一定要做到单一职责,类的设计尽量做到只有一个原因引起变化

ps:单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或类或方法设计的是否优良,但是“职责”和“变化原因”是不可以估量的,因项目而已,因环境而异


里氏替换原则

英文名:Liskov Substitution principle

基础回顾

继承的优点

  • 1.代码共享,减少创建类的工作量,每个之类都拥有父类的方法和属性;
  • 2.提高代码的重用性;
  • 3.子类可以形似父类,又异于父类,有自己的方法和属性;
  • 4.提高代码的可扩展性,实现父类的方法就可以“为所欲为”;
  • 5.提高产品或项目的开放性

继承的缺点

  • 1.继承是侵入性的,只要继承,就必须拥有父类的所有属性和方法
  • 2.降低代码的灵活度。子类必须拥有父类的属性和方法,让子类自由的世界里多了约束;
  • 3.增强了耦合性,当父类的常量、变量和方法被修改时,需要考虑子类的修改;

里氏替换两种定义:

  • 1.如果对每一个类型为S的对象o1, 都有类型为T的对象o2, 使得以T定义的所有程序P在所有的对象o1都代换成o2时, 程序P的行为没有发生变化, 那么类型S是类型T的子类型。
  • 2 .所有引用基类的地方都可以透明地使用其子类的对象。

含义

1:子类必须完全实现父类的方法(这里指的父类一般是接口或者抽象类);

注意:

  • 1在类中调用其它类时务必要使用父类或者接口(这样众多子类可以传入父类为参数的方法中
  • 2.如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖,聚合,组合等关系代替继承。

2.子类可以有自己的个性;

注意:向上转型是安全的,向下转型(downcast)是不安全的,从里氏替换原则来看,有子类出现的地方父类未必就可以出现

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

当子类的方法输入参数被放大了,这时候,子类和父类所对应的关系就是重载(方法名相同,输入参数不同)。如果子类的输入参数被缩小了。也就是子类的输入参数为父类的输入参数的子类的话,子类在没有重写父类的方法的时候,子类的方法会被执行,这样会引起业务逻辑混乱。换句话说,如果要执行如果要让子类的方法执行(与父类方法名相同),就必须重写父类的方法。

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

覆写的情况下,父类和子类的同名方法的输入参数相同,子类方法的返回值类型应该小于等于父类的返回值类型,也就是父类的返回值类型应该等于子类的返回值类型,或者父类的返回值类型是子类的返回值类型的父类。

总结
采用里氏替换原则的目的就是增强程序的健壮性,版本升级的时候也可以保持很好的兼容性,即使增加子类,原有的子类可以继续运行,在实际项目中,每个子类对应的不同业务含义,使用父类作为参数,传递不同的子类完成不同的业务逻辑!要尽量避免子类的”个性”


依赖倒置原则

英文名:Dependence Inversion Principle

何为依赖倒置:

先谈何为依赖正置,依赖正置是类间的依赖是实实在在的实现类之间的依赖,也就是面向实现编程,而编写程序需要是对现实事物进行抽象,抽象的接口是有了接口和抽象类,然后根据系统设计的需要产生抽象间的依赖,代替了传统思维中事物间的依赖,这就是倒置了!

含义:

  • 1.高层模块不应该依赖低层模块,两者都应该依赖其抽象;
  • 2.抽象不应该依赖细节;
  • 3.细节应该依赖抽象;

对应java中的表现就是

  • 1.模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;
  • 2.接口或抽象类不依赖于实现类;
  • 3.实现类依赖接口或者抽象类;

更精髓的定义就在于”面向接口编程”

例如:驾驶员开车,车就是一个接口,车的功能是跑,接口里有run方法,所有的车就必须继承这个接口,驾驶员开车的方法传入参数也必然是接口的实例;

优点

依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性;

注意:在java中,只要定义变量就必然有类型,一个变量可以有两种类型:表面类型和实际类型,表面类型是在定义的时候赋予的类型,实际类型是对象的类型,如
IDriver zhangSan = new Driver( ) ;表面类型是IDriver,实际类型是Driver,这里我的理解是:编译时是IDriver类型,zhangsan能调用的方法也只能是IDriver中存在的方法,但是运行时类型是Driver,调用的实际是实现类的方法。这里用到了向上转型,是安全的。

依赖的三种写法
依赖是可以传递,A对象依赖于B对象,B对象依赖于C对象,C对象依赖于D,只要记住关键的一点:只要做到抽象依赖,即便是有多层的依赖传递也无所畏惧!

  • 1.构造方法传递依赖对象(构造函数注入)

    public interface IDriver {
        //是司机就应该会驾驶汽车
        public void drive() ;
    }
    public class Driver implements IDriver{
        private ICar car;
        //构造函数注入
        public Driver(ICar _car) {
            this.car = _car;
        }
        //司机的主要职责就是驾驶汽车
        public void drive() {
            this.car.run() ;
        }
    }
    
  • 2.Setter方法传递依赖对象(在抽象中设置Setter方法声明依赖关系,这是Setter依赖注入)

    public interface IDriver {
        //车辆型号
        public void setCar(ICar car) ;
        //是司机就应该会驾驶汽车
        public void drive() ;
    }
    public class Driver implements IDriver{
        private ICar car;
        public void setCar(ICar car) {
        this. car = car;
        }
        //司机的主要职责就是驾驶汽车
        public void drive() {
        this.car.run() ;
        }
    }
    
  • 3.接口声明依赖对象(在接口方法中申明依赖对象;)

    public interface IDriver {
        //是司机就应该会驾驶汽车
        public void drive( ICar car) ;
    }
    

总结

依赖倒置原则的本质就是通过抽象(接口或者抽象类)使各个类或者模块的实现彼此独立,不互相影响,实现模块间的松耦合,我们在项目中使用的规则如下:

  • 1.每个类尽量都有接口或者抽象类,或者抽象类和接口两者都具备。(有了抽象才可以依赖倒置);
  • 2.变量的表面类型尽量使接口或者是抽象类;
  • 3.任何类都不应该从具体类派生;
  • 4.尽量不要复写基类的方法;
  • 5.结合里氏替换原则使用;

结合里氏替换原则:父类出现的地方子类就可以出现;

再结合本章得出通俗的规则:接口负责定义public属性和方法,并且声明与其他对象的依赖关系,抽象类负责公共构造方法的是实现,实现类负责准确实现业务逻辑,同时在适当的时候对父类进行细化。

ps:依赖倒置原则的优点在小型项目 中很难体现出来, 例如小于10个人月 的项目 , 使用简单的SSH架构, 基本上不费太大力气就可以完成, 是否采用依赖倒置原则影响不大。 但是, 在一个大中型项目 中, 采用依赖倒置原则有非常多的优点, 特别是规避一些非技术因素引起的问题。 项目 越大, 需求变化的概率也越大, 通过采用依赖倒置原则设计的接口或抽象类对实现类进行约束, 可以减少需求变化引起的工作量剧增的情况。 人员的变动在大中型项目 中也是时常存在的, 如果设计优良、 代码结构清晰, 人员变化对项目 的影响基本为零。 大中型项目 的维护周期一般都很长, 采用依赖倒置原则可以让维护人员轻松地扩展和维护。


接口隔离原则

英文名:Interface Segregation Principle

含义:

Clients should not be forced to depend upon interfaces that they don’t use.(客户端不应该依赖他不需要的接口)

The dependency of one class to another one should depend on the smallest possible interface.(类间的依赖关系应该建立在最小的接口上)

建立单一接口,不要建立臃肿庞大的接口;把一个臃肿的接口变更为多个独立的接口所依赖的原则就是接口隔离原则,接口是我们设计时对外提供的契约,通过分散定义多个接口,可以预防未来变更的扩散,提供系统的灵活性和可以维护性

接口隔离原则与单一职责原则的区别:

单一职责原则要求的是类和接口职责单一,注重的是职责,是业务逻辑上的划分;

接口隔离原则则是要求接口的方法尽可能的少;(职责单一并不为意味着接口的方法少)

接口隔离原则是对接口进行规范约束,其包括以下4层含义:

  • 1.接口要尽量小;接口隔离原则拆分接口时,首先必须满足单一职责原则;
  • 2.接口要高内聚;要求接口中尽量少公布public方法,接口时对外的承诺,承诺越少对系统的开发越有利,变更的风险越少,同时也有利于降低成本;
  • 3.制定服务;为单独的一个个体提供优良的服务;
  • 4.接口设计是有限度的;

实践中衡量的规则

  • 1.一个接口只服务于一个子模块或业务逻辑;
  • 2.通过业务逻辑压缩接口中的public方法;
  • 3.已经被污染了的接口,尽量去修改,若变更的风险较大,则采用适配器模式进行转化处理;
  • 4.了解环境,拒绝盲从;

迪米特法则

英文:Law of Demeter 又称为最少知识原则(Least Knowledge Principle)

定义:

一个对象应该对其他对象有最少的了解;

  • 1.只和朋友交流(避开与陌生类的交流,降低系统的耦合,提高系统的健壮性)
  • 2.朋友之间是有距离的;(耦合度要低,尽可能的减少public方法和public属性)
  • 3.是自己的就是自己的;(如果一个方法放在本类中,即不增加类间联系,也对本类不产生负面影响,那就放置在本类中);
  • 4.谨慎使用Serializable;

总结

迪米特法则的核心观念就是类间解耦,弱耦合,只有弱耦合了以后,类的复用率才可以提高,其要求的结果就是产生了大量的中转或跳转类,导致系统的复杂性提升,同事也为维护带来了难度。在使用中迪米特法则时候需要反复权衡,既做到让结构清楚,又做到高内聚低耦合;

开闭原则

英文名:Open Closed Principle

含义:Software entities like classes,and functions should be open for extension but closed for modifications

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

注意
开闭原则是对扩展开放,对修改关闭,并不意味着不做修改,底层模块的变化,必然要更高层模块进行耦合,否则就是一个孤立无援的代码片段。

开闭原则的重要性

  • 1.开闭原则对测试的影响。(原来的测试依然没有影响,因为我们是用过扩展来实现业务逻辑的修改)
  • 2.开闭原则可以提高复用性;
  • 3.开闭原则可以提高维护性;
  • 4.面向对象开发的要求(再设计时候要考虑到可能变化的因素,然后留下接口,等待”可能”变成”现实”);

如何使用开闭原则

  • 1.抽象约束
  • 2.元数据( metadata) 控制模块行为。(元数据通俗的讲就是配置参数,参数可以通过文件获取,也可以从数据库中获取,)
  • 3.制定项目章程
  • 4.封装变化(1.讲相同的变化封装到一个接口和抽象类中;2.将不同的变化封装到不同的接口或抽象类中,不应该有两个不同变化的出现在同一个接口和抽象类中)

ps:开闭原则是一个终极目标,任何人包括大师级人物都无法百分百做到,但朝这个方向努力,可以非常显著的改善一个系统的架构,真正做到”拥抱变化”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值