设计模式
1.请描述什么是依赖倒置原则,为什么有时候依赖倒置原则又被称为好莱坞原则?
依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
面向对象的开发使高层调用底层,高层依赖于底层,当底层变动时高层也要跟着变动,这就会导致模块的复用性降低而且大大提高了开发的成本。总结就是:
1、高层模块不应该依赖底层模块,二者都应该依赖抽象。
2、抽象不应该依赖细节,细节应该依赖抽象。
3、依赖倒置的中心思想是面向接口编程。
4、依赖倒置原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础搭建的架构要稳定的多。
5、使用接口或抽象类的目的是指定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类来完成。
2.请用接口隔离原则优化 Cache 类的设计,画出优化后的类图。
3.学习总结(面向对象的七种设计原则)
原则一:(SRP:Single responsibility principle)单一职责原则
核心:解耦和增强内聚性(高内聚,低耦合)
描述:类被修改的几率很大,因此应该专注于单一的功能。如果你把多个功能放在同一个类中,功能之间就形成了关联,改变其中一个功能,有可能中止另一个功能,这时就需要新一轮的测试来避免可能出现的问题。
单一职责的含义是:类的职责单一,引起类变化的原因单一。解释一下,这也是灵活的前提,如果我们把类拆分成最小的职能单位,那组合与复用就简单的多了,如果一个类做的事情太多,在组合的时候,必然会产生不必要的方法出现,这实际上是一种污染。
举个例子,我们在绘制图案的时候,用“点”组成图和用“直线”组成图,哪个更灵活呢?一定是“点”,它可以绘制任何图形,而直线只能绘制带有直线条的图案,它起码无法画圆。
单一职责的潜台词是:拆分到最小单位,解决复用和组合问题。
原则二:开闭原则(OCP:Open Closed Principle)
核心:对扩展开放,对修改关闭。即在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。根据开闭原则,在设计一个软件系统模块(类,方法)的时候,应该可以在不修改原有的模块(修改关闭)的基础上,能扩展其功能(扩展开放)。
解释一下就是,我们写完的代码,不能因为需求变化就修改。我们可以通过新增代码的方式来解决变化的需求。当然,这是一种理想的状态,在现实中,我们要尽量的缩小这种修改。开闭原则是设计模式的第一大原则,它的潜台词是:控制需求变动风险,缩小维护成本。
其他几种原则,都是为此原则服务的。
原则三:里氏替换原则(LSP:Liskov Substitution Principle)
核心:1.在任何父类出现的地方都可以用他的子类来替代(子类应当可以替换父类并出现在父类能够出现的任何地方)
2.子类可以有自己的个性。子类当然可以有自己的行为和外观了,也就是方法和属性
3.覆盖或实现父类的方法时输入参数可以被放大。即子类可以重载父类的方法,但输入参数应比父类方法中的大,这样在子类代替父类的时候,调用的仍然是父类的方法。即以子类中方法的前置条件必须与超类中被覆盖的方法的前置条件相同或者更宽松。
4.覆盖或实现父类的方法时输出结果可以被缩小。
此原则的含义是子类可以在任何地方替换它的父类。解释一下,这是多态的前提,我们后面很多所谓的灵活,都是不改变声明类型的情况下,改变实例化类来完成的需求变更。当然,继承的特性看似天然就满足这个条件。但这里更注重的是继承的应用问题,我们必须保证我们的子类和父类划分是精准的。
里氏替换原则的潜台词是:尽量使用精准的抽象类或者接口。
原则四:依赖倒转原则(DIP:Dependence Inversion Principle) 依赖倒置原则或依赖反转原则
核心:要依赖于抽象,不要依赖于具体的实现
1.高层模块不应该依赖低层模块,两者都应该依赖其抽象(抽象类或接口)
2.抽象不应该依赖细节(具体实现)
3.细节(具体实现)应该依赖抽象。
想要理解依赖倒置原则,必须先理解传统的解决方案。面相对象的初期的程序,被调用者依赖于调用者。也就是调用者决定被调用者有什么方法,有什么样的实现方式,这种结构在需求变更的时候,会付出很大的代价,甚至推翻重写。
依赖倒置原则就是要求调用者和被调用者都依赖抽象,这样两者没有直接的关联和接触,在变动的时候,一方的变动不会影响另一方的变动。
其实,依赖倒置和前面的原则是相辅相成的,都强调了抽象的重要性。
依赖倒置的潜台词是:面向抽象编程,解耦调用和被调用者。
三种实现方式:
1.通过构造函数传递依赖对象
2.通过setter方法传递依赖对象
3.接口声明实现依赖对象
原则五:接口分离原则(ISP:Interface Segregation Principle)
核心:不应该强迫客户程序依赖他们不需要使用的方法。
描述:一个接口不需要提供太多的行为,一个接口应该只提供一种对外的功能,不应该把所有的操作都封装到一个接口当中.
分离接口的两种实现方法:
1.使用委托分离接口。(Separation through Delegation)
2.使用多重继承分离接口。(Separation through Multiple Inheritance)
接口隔离原则可以说是单一职责的必要手段,它的含义是尽量使用职能单一的接口,而不使用职能复杂、全面的接口。很好理解,接口是为了让子类实现的,如果子类想达到职能单一,那么接口也必须满足职能单一。相反,如果接口融合了多个不相关的方法,那它的子类就被迫要实现所有方法,尽管有些方法是根本用不到的。这就是接口污染。
接口隔离原则的潜台词是:拆分,从接口开始。
原则六:合成复用原则(CRP:Composite Reuse Principle)
核心:尽量使用对象组合,而不是继承来达到复用的目的。该原则就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分:新的对象通过向这些对象的委派达到复用已有功能的目的。
复用的种类:
1.继承
2.合成聚合
注:在复用时应优先考虑使用合成聚合而不是继承
此原则的含义是,如果只是达到代码复用的目的,尽量使用组合与聚合,而不是继承。这里需要解释一下,组合聚合只是引用其他的类的方法,而不会受引用的类的继承而改变血统。
继承的耦合性更大,比如一个父类后来添加实现一个接口或者去掉一个接口,那子类可能会遭到毁灭性的编译错误,但如果只是组合聚合,只是引用类的方法,就不会有这种巨大的风险,同时也实现了复用。
组合聚合复用原则的潜台词是:我只是用你的方法,我们不一定是同类。
原则七:迪米特原则(LOD:Law of Demeter)又叫最少知识原则
核心思想:一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。(类间解耦,低耦合)意思就是降低各个对象之间的耦合,提高系统的可维护性;在模块之间只通过接口来通信,
而不理会模块的内部工作原理,可以使各个模块的耦合成都降到最低,促进软件的复用
注:
1.在类的划分上,应该创建有弱耦合的类;
2.在类的结构设计上,每一个类都应当尽量降低成员的访问权限;
3.在类的设计上,只要有可能,一个类应当设计成不变;
4.在对其他类的引用上,一个对象对其它对象的引用应当降到最低;
5.尽量降低类的访问权限;
6.谨慎使用序列化功能;
7.不要暴露类成员,而应该提供相应的访问器(属性)
迪米特原则要求尽量的封装,尽量的独立,尽量的使用低级别的访问修饰符。这是封装特性的典型体现。
一个类如果暴露太多私用的方法和字段,会让调用者很茫然。并且会给类造成不必要的判断代码。所以,我们使用尽量低的访问修饰符,让外界不知道我们的内部。这也是面向对象的基本思路。这是迪米特原则的一个特性,无法了解类更多的私有信息。
另外,迪米特原则要求类之间的直接联系尽量的少,两个类的访问,通过第三个中介类来实现。
迪米特原则的潜台词是:不和陌生人说话,有事去中介。
评论