Seven Object-Oriented Design Principles to Design Scalable Programs with High Cohesion and Low Coupling

1. Single Responsibility Principle

        An interface or class is responsible for only one responsibility.

       Single responsibility applies to methods, and a method does as much as possible only one thing. 

       For a single responsibility, it is recommended that an interface must achieve a single responsibility, and the design of the class should try to ensure that there is only one reason for the change.

        The more responsibilities a class (from modules to methods) undertakes, the less likely it is to be reused, and a class has too many responsibilities, which is equivalent to coupling these responsibilities together. When responsibilities change, it may affect the operation of other responsibilities. Therefore, these responsibilities should be separated, and different responsibilities should be encapsulated in different classes, that is, different reasons for changes should be encapsulated in different classes. If multiple responsibilities are always at the same time Changes can be encapsulated in the same class.

  benefit:

       1. It can reduce the complexity of the class. A class is only responsible for one responsibility, and its logic is definitely much simpler than responsible for multiple responsibilities

        2. The complexity is low, and the readability is naturally improved.

        3. High maintainability and low risk. If the single responsibility of the interface is good, an interface modification only affects the corresponding implementation class. It has no effect on other interfaces, which is very helpful to the scalability and maintainability of the system.  

 

 

2. Liskov Substitution Principle

       All references to the base class (parent class) must be able to be replaced with the object of its subclass, that is, if a base class object is replaced with its subclass object in the software, the program will not generate any errors and exceptions, instead Come here, it will not be established,

        The Liskov substitution principle is one of the important ways to implement the open-closed principle. When calling other classes in a class, be sure to use the base class object (parent class or interface), pass parameters, define member variables, define local variables, and determine the method return. The Liskov Substitution Principle can be used for all types. For base class programming, specific subclasses are determined when the program is running.

       If the subclass cannot fully implement the method in the parent class, or the parent class method implemented by the subclass has a different meaning from the parent class method, it is recommended to break the parent-child inheritance relationship and use dependencies, aggregation, composition and other relationships instead of inheritance.

        The Liskov substitution principle is commonly said: subclasses can extend the functions of the parent class, but cannot change the original functions of the parent class. 1. The subclass can implement the function of the parent class, but cannot change the original function of the parent class. 2. When the method of the subclass overrides the method of the parent class, the preconditions (method parameters) of the method are higher than those of the parent class method. Input parameters are more relaxed 3. When the subclass method implements the abstract method of the parent class, the post-conditions of the method (the return value of the method) are stricter than those of the parent class.

        

         

 

 

 3. Dependency Inversion Principle

        Dependency between modules occurs through abstraction, and there is no direct dependency relationship between implementation classes. The dependency relationship is generated through interfaces or abstract classes.

        An interface or abstract class does not depend on the implementation class (the interface should be followed by the implementation class).

        Implementing classes depend on interfaces or abstract classes.

        The Dependency Inversion Principle requires us to refer to high-level abstract classes as much as possible when passing parameters in program code or in association relationships, that is, using interfaces and abstract classes for variable type declarations, parameter type declarations, method return type declarations, and data types instead of using concrete classes to do these things.

        In order to ensure the application of this principle, a concrete class should only implement the methods declared in the interface or abstract class, and not give redundant methods, otherwise it will not be able to call the new methods added in the subclass

        Dependency inversion principle is interface-oriented programming OOD (Object-Oriented Design): the interface is responsible for defining public properties and methods, and declaring dependencies with other objects, the abstract class is responsible for the implementation of the public structure, and the implementation class accurately implements business logic.

        Dependency 1: The constructor passes the dependent object

        Dependency 2: Setter Dependency Injection

        Dependency 3: The interface declares the dependent object

 

 

 4. Interface isolation principle

        Use multiple specialized interfaces instead of a single general interface, i.e. the client should not depend on those interfaces it does not need.

       An interface serves only one submodule or business logic

        Through in-depth understanding of the public methods in the business logic compression interface, achieve "full body "

       与单一职责原则区别,单一职责原则注重的是职责,而接口隔离原则注重对接口依赖的隔离。单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节,而接口隔离原则主要约束接口,主要针对抽象,针对程序整体框架的构建。

        接口尽量小,但是要有限度,接口细化可以提高程序设计的灵活性,但如果过小,会导致接口过多,使设计复杂化。

 

 5.迪米特法则

        问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类影响也越大。

        解决:一个软件实体应当尽可能少地与其他实体发生相互作用,迪米特法则可降低系统的耦合度,使类与类之间保持松散的耦合关系

      一 个类只和朋友交流,不与陌生类交流,其朋友包括以下几类:

      (1) 当前对象本身(this);

      (2) 以参数形式传入到当前对象方法中的对象;

      (3) 当前对象的成员对象;

      (4) 如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友;

      (5) 当前对象所创建的对象。

        出现在方法体内部的类不属于朋友不要出现getA().getB().getC(),除非每个点后面都返回同一个对象,类与类之间的关系是建立在类间的,而不是方法间,因此一个方法尽量不要引入一个类中不存在的对象。

       在类的划分上,应当尽量创建松耦合的类,类之间的耦合度越低,就越有利于复用,一个处在松耦合中的类一旦被修改,不会对关联的类造成太大波及;在类的结构设计上,每一个类(朋友)都应当尽量降低其成员变量和成员函数的访问权限;在类的设计上,只要有可能,一个类型应当设计成不变类;在对其他类的引用上,一个对象对其他对象的引用应当降到最低。

        如果与多个朋友交互,可以通过引入一个合理的第三者来降低现有对象之间的耦合度

           迪米特法则的核心是类间解耦,只有弱耦合,类之间的复用率才可以提高,其要求的结果就是产生了大量的中转或跳转类,导致系统复杂性提高,同时也为维护带来了难度,所以在采用迪米特法则时要反复权衡,既要结构清晰,又要搞内聚低耦合。

        一般一个类访问另一个类跳转不要超过2 次。

 

6.开闭原则

       一个软件实体应当对扩展开放,对修改关闭。其含义是说一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。

     实体:软件模块、抽象和类、方法。

     在面向对象的设计中,所有的逻辑都是从原子逻辑组合而来的,而不是在一个类中独立实现一个业务逻辑,只有这样的代码才可以复用,粒度越小,被复用的可能性就越大,复用可以减少代码量,避免相同的逻辑分散在多个角落。避免日后的维护人员为了修改一个微小的缺陷而在整个项目中到处查找相关代码。

        开闭原则可以提高维护性,扩展一个类相对修改一个类要舒服很多。

        抽象层应尽量保持稳定,一旦确定即不允许修改。接口或者抽象类一旦定义,就应该立即执行,不能有修改接口的思想。除非是彻底的大返工。

     

7.合成复用原则

    尽量使用对象组合,而不是继承来达到复用的目的。

     复用时要尽量使用组合/聚合关系(关联关系),少用继承。来使用一个已有的对象成为新对象的一部分,新对象通过委派调用已有对象的方法达到复用功能的目的。

      在面向对象设计中,可以通过两种方法在不同的环境中复用已有的设计和实现,即通过组合/聚合关系或通过继承,但首先应该考虑使用组合/聚合组合/聚合可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少;其次才考虑继承,在使用继承时,需要严格遵循里氏代换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及系统的复杂度,因此需要慎重使用继承复用

      通过继承来进行复用的主要问题在于继承复用会破坏系统的封装性,因为继承会将基类的实现细节暴露给子类,由于基类的内部细节通常对子类来说是可见的,所以这种复用又称“白箱”复用,如果基类发生改变,那么子类的实现也不得不发生改变;从基类继承而来的实现是静态的,不可能在运行时发生改变,没有足够的灵活性;而且继承只能在有限的环境中使用(如类没有声明为不能被继承)。

       由于组合或聚合关系可以将已有的对象(也可称为成员对象)纳入到新对象中,使之成为新对象的一部分,因此新对象可以调用已有对象的功能,这样做可以使得成员对象的内部实现细节对于新对象不可见,所以这种复用又称为“黑箱”复用,相对继承关系而言,其耦合度相对较低,成员对象的变化对新对象的影响不大,可以在新对象中根据实际需要有选择性地调用成员对象的操作;合成复用可以在运行时动态进行,新对象可以动态地引用与成员对象类型相同的其他对象。

      一般而言,如果两个类之间是“Has-A”的关系应使用组合或聚合,如果是“Is-A”关系可使用继承。"Is-A"是严格的分类学意义上的定义,意思是一个类是另一个类的"一种";而"Has-A"则不同,它表示某一个角色具有某一项责任。

 

 

 

名词解释:

 

关联关系:类之间的联系

public class B {
	private A a;
	........
}

public class A{
	........
}

 

 

聚合关系: 成员类是整体类的一部分,即成员对象是整体对象的一部分,但是成员对象可以脱离整体对象独立存在

public class B {
	private A a;

	public B(A a) {
		this.a = a;
	}

	public void setA(A a) {
		this.a = a;
	}
}

public class A{
	........
}

 

 

 

 

组合关系:也是整体与部分的关系,但是整体与部分不可以分开。

       也表示类之间整体和部分的关系,但是组合关系中部分和整体具有统一的生存期。一旦整体对象不存在,部分对象也将不存在,部分对象与整体对象之间具有同生共死的关系。

public class B {
	private A a;

	public B() {
		a = new A();
	}
}

public class A{
	........
}
 

 下面是粘过来的

设计原则名称

  

使用频率

单一职责原则

(Single Responsibility Principle, SRP)

一个类只负责一个功能领域中的相应职责

★★★★☆

开闭原则

(Open-Closed Principle, OCP)

软件实体应对扩展开放,而对修改关闭

★★★★★

里氏代换原则

(Liskov Substitution Principle, LSP)

所有引用基类对象的地方能够透明地使用其子类的对象

 

★★★★★

依赖倒转原则

(Dependence  Inversion Principle, DIP)

抽象不应该依赖于细节,细节应该依赖于抽象

★★★★★

接口隔离原则

(Interface Segregation Principle, ISP)

使用多个专门的接口,而不使用单一的总接口

★★☆☆☆

合成复用原则

(Composite Reuse Principle, CRP)

尽量使用对象组合,而不是继承来达到复用的目的

 

★★★★☆

迪米特法则

(Law of Demeter, LoD)

一个软件实体应当尽可能少地与其他实体发生相互作用

★★★☆☆

【作者:刘伟  http://blog.csdn.net/lovelion

 

 

参考书籍:《设计模式之禅》

博客参考: http://my.csdn.net/LoveLion

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326403237&siteId=291194637