软件编程有多年工业界实践的经验沉淀,这些原则、法则是指导我们设计、编码的方法论。本文只针对OOD
。
我尽量一句话概括一项原则、法则:
GRASP
General Responsibility Assignment Software Patterns (or Principles), abbreviated GRASP, is a set of “nine fundamental principles in object design and responsibility assignment”
通用职责分配原则,缩写GRASP
,包含九种OOP
设计基础原则。
信息隐藏 | 信息专家 | 封装
Information hiding(Information expert) interchangeable with term Encapsulation
将具备共同含义、变化频率的部分封装起来,并通过接口隔离实现,通过访问权限隔离访问。
特性:高内聚、低耦合。
创建者 | Creator | Factory
In object-oriented programming (OOP), a factory is an object for creating other objects – formally a factory is a function or method that returns objects of a varying prototype or class[1] from some method call, which is assumed to be “new”.[a] More broadly, a subroutine that returns a “new” object may be referred to as a “factory”, as in factory method or factory function.
OOP
中,创建者、工厂,负责特定对象的创建。
Controller | 非UI场景
The controller pattern assigns the responsibility of dealing with system events to a non-UI class that represents the overall system or a use case scenario. A controller object is a non-user interface object responsible for receiving or handling a system event.
Controller
负责接收、处理系统事件。与MVC
中的C
含义一致。
相关模式:命令模式、门面模式、分层架构、纯虚构。
转发 | Indirection
The indirection pattern supports low coupling and reuses potential between two elements by assigning the responsibility of mediation between them to an intermediate object.
转发模式:使用一个中间层转发对接前后的元素或层,解耦了前后元素,并且复用了已有能力,起分配作用。
特性:低耦合、复用能力。
低耦合 | Low coupling
Coupling is a measure of how strongly one element is connected to, has knowledge of, or relies on other elements.
以上为耦合的定义。而低耦合(松耦合)是一种评估效果的模式:
- 类与类之间是否依赖是更少、更低一层的;
- 对一个类的修改是否对其他类有更少的影响;
- 有更多复用的可能性;
高内聚 | High cohesion
High cohesion is an evaluative pattern that attempts to keep objects appropriately focused, manageable and understandable.
与低耦合属于同类,均为评估效果的模式:
- 对象职责是否明确、专注;
- 对象是否更好管理;
- 代码是否易懂;
多态 | Polymorphism
In programming language theory and type theory, polymorphism is the provision of a single interface to entities of different types[1] or the use of a single symbol to represent multiple different types.[2] The concept is borrowed from a principle in biology where an organism or species can have many different forms or stages.
受生物学启发,一个生物或者有机体可以有多种形态、阶段。
同理:
- 在编程语言理论中,多态通过单个接口,提供了多种类型实现。
- 在类型理论研究中,单一符号可以表示多种类型。
实现分类:
-
Ad hoc polymorphism 特定多态
方法、函数、修饰符的重载。
-
Parametric polymorphism 参数类型多态
泛型多态。泛型不指定实际调用时的具体类型,而是用通用符号进行函数定义。
-
Subtyping 子类型多态
定义时只指定公共父类符号。
隔离变化 | 开闭原则 | Protected variations
隔离变化 | 开闭原则 | Protected variations
The protected variations pattern protects elements from the variations on other elements (objects, systems, subsystems) by wrapping the focus of instability with an interface and using polymorphism to create various implementations of this interface.
识别预测可能的变化点,通过接口或者抽象隔离变化。
纯虚构 | Pure fabrication
A pure fabrication is a class that does not represent a concept in the problem domain, specially made up to achieve low coupling, high cohesion, and the reuse potential thereof derived (when a solution presented by the information expert pattern does not). This kind of class is called a “service” in domain-driven design.
虚构层、虚构对象没有对应的领域概念,是为了高内聚、低耦合、复用(内聚了信息专家没有的信息)创造出的代码表示。
DDD
、MVC
中我们称虚构层为service
。
特性:高内聚、低耦合。
SOLID
单一职责原则
Single-responsibility principle A class should have one, and only one, reason to change.
一个类只应该负责一件事。当针对这个类需要变更时,只能由一个理由驱动。
开闭原则
Open–closed principle You should be able to extend a classes behavior, without modifying it.
OOP
背景下,软件实体(类、模块、函数)对拓展开放,对修改封闭。
当需要增加、修改功能时,不要修改源码(包括原来的二进制文件),通过拓展来完成变更。
里式替换原则
Liskov substitution principle
Liskov’s notion of a behavioural subtype defines a notion of substitutability for objects; that is, if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program (e.g. correctness).
Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.
Derived classes must be substitutable for their base classes.
父类实例可以在不修改任何类属性的前提下,替换为子类实例。
接口隔离原则
Interface segregation principle
Many client-specific interfaces are better than one general-purpose interface.
小的、精确的接口,比大的接口更好。通过约束接口来优化依赖关系。
依赖倒置原则
Dependency inversion principle
Depend upon abstractions, [not] concretions.
依赖接口,不依赖实现。
组合优于继承
Composition over inheritance
当我们想重用代码或者实现多态时,要优先使用组合的方式。
迪米特法则
Law of Demeter LOD
又叫最少知识法则,面向解耦的目的,调用方对被调用方的内部结构、实现知道的越少越好。
控制反转法则
IoC(Inversion of Control)
通过框架控制对象创建、流程,用于实现拓展性、模块化。
OOP
下的实现方式:
- service locator pattern
- 服务定位设计模式
- 使用抽象层封装了寻找真实业务处理者的逻辑
- 举例:
JNDI
- dependency injection
- 依赖注入
- Constructor
- Parameter
- Setter
- Interface
- Method
- 举例:
Spring
的依赖注入容器
- 依赖注入
- contextualized lookup
- 上下文寻址
- 也叫 Contextualized Dependency Lookup (CDL)
- todo: Contextualized Dependency Lookup (CDL) is similar, in some respects, to Dependency Pull, but in CDL,lookup is performed against the container that is managing the resource, not from some central registry,and it is usually performed at some set point
- template method design pattern
- 模板方法设计模式
- strategy design pattern
- 策略设计模式
KISS
KISS, an acronym for keep it simple, stupid, is a design principle noted by the U.S. Navy in 1960.
The KISS principle states that most systems work best if they are kept simple rather than made complicated; therefore, simplicity should be a key goal in design, and unnecessary complexity should be avoided.
KISS法则是说:我们的系统能够运行良好的一大原因是足够简单。因此,简单、简洁、避免不必要的复杂是我们设计的核心目标。
变体:
- Keep it simple, silly
- keep it short and simple
- keep it short and sweet
- keep it simple and straightforward
- keep it small and simple
- keep it simple, soldier
- keep it simple, sailor
- keep it sweet and simple
DRY
The DRY principle is stated as “Every piece of knowledge must have a single, unambiguous, authoritative representation within a system”. The principle has been formulated by Andy Hunt and Dave Thomas in their book The Pragmatic Programmer. They apply it quite broadly to include “database schemas, test plans, the build system, even documentation”.
同一系统内的同一知识应该有明确、权威可信的唯一表示。
WET 反模式
write everything twice write every time waste everyone’s time
反模式:无脑拷贝、重写代码。
AHA
AHA stands for “avoid hasty abstractions”, described by Kent C. Dodds as optimizing for change first, and avoiding premature optimization.[8] and was influenced by Sandi Metz’s “prefer duplication over the wrong abstraction”.
避免草率的抽象。面对变更先做修改,避免过早优化。
YAGNI
“You aren’t gonna need it”(YAGNI) is a principle which arose from extreme programming (XP) that states a programmer should not add functionality until deemed necessary. XP co-founder Ron Jeffries has written: “Always implement things when you actually need them, never when you just foresee that you need them.”
只有在真正需要的时候再去实现新的逻辑,尽可能复用已有代码。
Document Your Code
Any senior developer will stress the importance of documenting your code with proper comments. All languages offer them; you should make it a habit to write them. Leave comments to explain objects, enhance variable definitions, and make functions easier to understand.
注释、文档与代码同样重要。使用注释解释对象、变量含义,同时使得函数更易读。
包管理法则
前三项关注包内聚,即包内应该放什么。 后三项关注包解耦,即关注包与包之间的关系、结构。
发布等于重用
REP The Release Reuse Equivalency Principle The granule of reuse is the granule of release.
发布的粒度就是重用的粒度。
封装变更
CCP The Common Closure Principle Classes that change together are packaged together.
一起变更的类应该放在同一个包下。即关注类变更的频率、规律。使用包封装这种变化。
封装重用
CRP The Common Reuse Principle Classes that are used together are packaged together.
一起使用的类应该放在同一个包下。即关注类被使用的场景。
没有循环依赖
ADP The Acyclic Dependencies Principle The dependency graph of packages must have no cycles.
包与包之间的依赖禁止出现环。
面向稳定的依赖
SDP The Stable Dependencies Principle Depend in the direction of stability.
保证依赖都是稳定的。
面向抽象的依赖
SAP The Stable Abstractions Principle Abstractness increases with stability.
依赖抽象,提高依赖的稳定性「变化的往往是实现」。