15:对于单一职责原则,如何判断某个类的职责是否单一?
1:概念
单一职责原则:A Class or module should have a single reponsibily。一个类或者模块只负责一个职责。
不要设计大而全的类,要设计粒度小,功能单一的类。
2:如何判断类的职责是否单一?
不同应用场景,不同阶段的需求背景下,对同一个类的职责是否单一的判定,可能是不一样的。
我们可以先实现一个粗粒度的类,然后在业务发展过程中拆分成细粒度的类。也就是所谓的持续重构。
提供几条判断原则:
1:类中的代码行数、函数、属性过多
2:类依赖的类过多
3:私有方法过多,考虑抽离到public类中提供复用
4:类名不好取,业务名称难概括
5:类中的方法大量集中在操作某几个属性
3:类的职责是否设计的越单一越好?
答案是否定的。最终目的是提高代码的可读性、可扩展性、复用性等。
16:如何做到“对扩展开放、修改关闭”?扩展和修改指什么?
大部分设计模式都是为了解决代码的扩展性问题而存在的,主要遵从的设计原则就是“开闭原则”
sofeware entity should be open for extension, but closed for modification。(对扩展开放,对修改关闭)
1:修改代码就意味着违背开闭原则吗?
没有破坏原有代码的正常运行,没有破坏原有的单元测试,我们就可以说这是一个合理的代码改动。
尽量让修改操作更集中、更少、更上层,尽量让最核心、最复杂的那部分代码符合开闭原则。
2:如何做到“对扩展开放、修改关闭”
开闭原则,讲的就是代码的扩展性问题,是判断一段代码是否易扩展的金标准。
偏向顶层的指导思想:具备扩展意识、封装意识、抽象意识。
具体的方法论:
23种设计模式,大部分都是为了解决代码的扩展性问题而总结出来的,都是以开闭原则为指导原则。
最常用来提高代码扩展性的方法有:多态、依赖注入、基于接口而非实现编程。
设计模式有:装饰、策略、模板、职责链、状态等。
3:如何在项目中灵活运用开闭原则?
变动可能性高、实现成本低,可以事先做好扩展性设计。
变动可能性低、实现成本高,可以先实现后面再考虑重构。
开闭原则也不是没有成本的,我们需要考虑扩展性和可读性之间的平衡。
17:里式替换跟多态有何区别?哪些代码违背了LSP?
1:概念:子类对象能够替换程序中父类对象出现的一切地方,并且保证程序逻辑不变,正确性不被破坏。
2:多态与里式替换原则的区别
多态:面向对象编程的一大特性,也是面向对象编程的一种语法,是一种代码实现的思路。
里式替换原则:用来指导继承关系中子类该如何设计,子类的设计要保证在替换父类的时候不改变程序的逻辑以及不破坏原有程序的正确性。
3:哪些代码违背了LSP?
子类设计的时候,要遵守父类的行为约定(或者叫协议)。
违反里式替换原则的例子:
1:子类违背父类声明要实现的功能
2:子类违背父类对输入、输出、异常的约定
3:子类违背父类注释中所罗列的任何特殊说明
18:接口隔离原则有哪三种应用?原则中的接口该如何理解?
1:概念:Clients should not be forced to depend upon interaces that they do not use。客户端不应该强迫依赖它不需要的接口。
接口可以理解为三种东西:
1.一组api接口集合 (多个interface实现不同功能)
2.单个api接口或函数 (一个interface多个不同函数实现不同功能)
3.OOP中的接口概念 (interface设计要尽量单一,不要让接口的实现类和调用类依赖不需要的接口函数)
2:接口隔离原则与单一职责原则的区别
单一职责原则针对的是模块、类、接口的设计。
接口隔离原则,侧重接口的设计,另外提供了一种判断标准:如果调用者只使用部分接口或接口的部分功能,那接口的设计就不够职责单一。
19:控制反转、依赖反转、依赖注入这三者有何区别和联系?
1:控制反转
控制:对程序执行流程的控制。
反转:流程的控制权从“程序员”反转到“框架”
控制反转,并不是一种具体的实现技巧,而是一个比较笼统的设计思想,一般用来指导框架层面的设计。
2:依赖注入
不同new()的方式在类内部创建依赖类对象,而是将依赖的类对象,在外部创建好之后,通过构造函数、函数传参等方式传递(或注入)给类使用。
提供了代码的扩展性,可以灵活替换依赖的类。
它是编写可测试性代码最有效的手段。
3:依赖注入框架
简单配置一下所有需要创建的类对象、类与类之间的依赖关系,就可以实现由框架来自动“创建对象”、“管理对象的生命周期”、“依赖注入”等原本由程序员来做的事情。
4:依赖反转原则
高层模块不要依赖低层模块。
高层模块和底层模块通过抽象来互相依赖。
抽象不要依赖具体的细节,具体实现细节依赖抽象。
->用来指导框架层面的设计。
20:我为何说KISS、YAGNI原则看似简单,却经常被用错?
1:代码函数越少就越“简单”吗? (不一定)
2:代码逻辑复杂就违背KISS原则吗?
本身就复杂的问题,用负责的方法解决,就不违背kiss原则。
如何写出满足kiss原则的代码?
1:不要使用同事可能不懂的技术来实现代码。
2:不要重复造轮子,要善于使用已经有的工具类库。
3:不要过度优化。使用一些奇技淫巧来优化代码,牺牲代码的可读性。
评判代码简单,有一个很有效的方式:code review。
越能用简单的方法解决复杂的问题,越能体现一个人的能力。
3:YAGNI原则和KISS是一回事吗?
KISS原则讲的是“如何做”的问题(尽量保证简单)
YAGNI原则说的是“要不要做”的问题(不需要就不做)
?
21:重复的代码就一定违背DRY原则吗?如何提高代码的复用性?
1:概念:不要重复自己。Don’t repeat yourself。
2:三种典型的代码重复情况
1:实现逻辑重复
2:功能语义重复
3:代码执行重复
3:怎么提高代码的复用性?
1:减少代码耦合
2:满足单一职责原则
3:模块化
4:业务和非业务逻辑分开
5:通用代码下沉
6:继承、多态、抽象、封装
7:应用模块等设计模式
22:如何用迪米特法则实现“高内聚、松耦合”?
1:何为“高内聚、松耦合”?
比较通用的设计思想,可以用来指导不同粒度代码的设计与开发,比如系统、模块、类、甚至是函数。
也可以应用到不同的开发场景中,比如微服务、框架、组件、类库等。
2:高内聚(形容单个类)
相近功能的代码应该放在同一个类中,不相近功能的代码不要放在同一个类中。
3:松耦合(形容类与类之间)
类与类之间的依赖关系简单清晰。即使两个类有依赖关系,一个类的代码改动不会或者很少导致依赖类的代码改动。
4:迪米特法则,也称为“最小知识原则”
每个模块只应该了解那些与它关系密切的模块的有限知识。或者说每个模块只和自己的朋友说话,不和陌生人说话。
|