Seven principles: Open and close principle, Richter substitution principle, dependency reversal principle, synthesis/aggregation multiplexing principle, Dimitri rule, interface isolation principle, single duty principle.
The open and closed principle is the cornerstone of object-oriented reusable. The other six principles are instruments and tools.
Details of the rules (reproduced in this section)
http://kb.cnblogs.com/page/214010/
Just as Newton's three laws are positioned in classical mechanics, the "open-close" principle (open-closed Principle) is the cornerstone of object-oriented, reusable designs (object oriented design or OOD). Other design principles (the Richter substitution principle, the dependency reversal principle, the synthesis/aggregation multiplexing principle, the Dimitri rule, the Interface isolation principle) are the means and tools for realizing the "open-close" principle.
First, "open- principle (open-closed PRINCIPLE,OCP )
1.1 definition and advantages of the "open- close" principle
1) Definition: A software entity should be open to extensions, closed to modifications (software entities should be open for extension, but closed for modification.). That is, when designing a module, it should be allowed to be extended without modification.
2) Advantages of a system that satisfies the "open-close" principle
A) by extending existing software systems, new behaviors can be provided to meet the new requirements of the software, adapting and flexible to the changing software systems.
b) Existing software modules, especially the most important abstraction layer module can not be modified, which makes the software system in the change has some stability and continuity.
c) Such a system satisfies both reusability and maintainability.
1.2 How to Realize "open- close" principle
In object-oriented design, it is not allowed to change the abstraction layer of the system, but the implementation layer of the system is allowed to extend. In other words, define a once and for all abstract design layer, allowing as many behaviors as possible to be implemented at the implementation level.
The key to solving the problem lies in abstraction, which is the first core essence of object-oriented design.
The abstraction of a thing is essentially a generalization of its essence. Abstract let us seize the most important things, from a higher level to think. This reduces the complexity of thinking, and we don't have to think about that much at the same time. In other words, we encapsulate the nature of things and see no details.
In object-oriented programming, by means of abstract classes and interfaces, the characteristics of specific classes are defined as abstract layers, relatively stable, without change, so as to satisfy the "close to modify", and the concrete classes derived from abstract classes can change the behavior of the system, thus satisfying the "open to extended".
When you extend an entity, you do not have to change the source code or the binaries of the software. The key is abstraction.
1.3 packaging principles for variability
The "open-close" principle is also the "encapsulation Principle of variability" (Principle of encapsulation of variation, EVP). That is to find a variable element of the system and encapsulate it. In other words, what may change in your design should be made into an abstraction layer and encapsulated instead of what will cause design changes to be encapsulated.
The "Packaging principle for variability" means:
A) a variability should not be scattered in many corners of the code, but should be encapsulated into an object. The different appearances of the same variability imply that the same inherits the specific subclasses in the hierarchy. Therefore, you can expect the emergence of an inheritance relationship here. Inheritance is a way to encapsulate changes, not just to generate special objects from generic objects.
b) One type of variability should not be mixed with another variability. The authors argue that if the inheritance structure of a class diagram is more than two layers, it would probably mean that there are two different kinds of variability mixed together.
Design with the "denatured encapsulation Principle" allows the system to adhere to the "on-and-off" principle.
Even if the principle of "open-close" cannot be fully achieved, efforts in this direction can significantly improve the structure of a system.
Second, the principle of substitution of the Richter scale (Liskov Substitution Principle, LSP)
2.1 Concept
Definition: If each object of type T1 is O1, there is an object O2 of type T2, so that all program P defined by T1 is substituted for O1 of all object O2, the behavior of program p does not change, then type T2 is a subtype of type T1.
That is, if a software entity is using a base class, then it must apply to its subclasses. And it does not perceive the difference between a base class object and a subclass object. That is, in the software, the base class is replaced by its subclasses, the behavior of the program has not changed.
The reverse substitution is not true, and if a software entity uses a subclass, it does not necessarily apply to the base class.
Where any base class can appear, subclasses must be able to appear.
The design of the contract-based design and the abstraction of the public part as the abstract base class.
The relationship between the substitution principle of 2.2 and the principle of "open- closed"
The key step in implementing the "open-close" principle is abstraction. The inheritance relationship between the base class and the subclass is the embodiment of abstraction. Therefore, the principle of substitution of the Richter scale is the specification of concrete steps to achieve abstraction.
Violating the principle of the Richter substitution means violating the principle of "open-closed" and vice versa.
Third, Dependency Reversal Principle ( dependence inversion principle, DIP )
3.1 concept
Dependency Reversal principle is to rely on the abstraction, do not rely on the implementation. (abstractions should not depend upon details. Details should depend upon abstractions.) to program for the interface, do not program for implementation. (Program to a interface, not a implementation.)
This means that you should use interfaces and abstract classes for variable type declarations, parameter type declarations, method return type descriptions, and conversion of data types. Instead of using specific classes for variable type declarations, parameter type declarations, method return type descriptions, conversion of data types, and so on. To ensure that this is done, a concrete class should implement only the methods that are declared in the interface and the abstract class, not the redundant methods.
The traditional process system design method tends to make the high-level module depend on the lower layer module, the abstraction level relies on the concrete level. The reversal principle is to reverse the false dependency.
The important principle of object-oriented design is to create abstractions, and to materialize from abstract, materialized to give different implementations. An inheritance relationship is an export from abstraction to materialization.
The abstraction layer contains the business logic of the application system and the macro-strategic decision which is important to the whole system, which is the embodiment of inevitability. The specific level contains some minor implementation-related algorithms and logic, as well as tactical decisions, with considerable contingency choices. Specific levels of code are constantly changing and cannot avoid errors.
From the perspective of reuse, high-level modules should be reused, and is the focus of reuse, because it contains an application system the most important macro business logic, is more stable. In the traditional process design, reuse is focused on the reuse of the concrete level module.
The principle of dependency reversal is the "inversion" of the traditional process design method, which is an effective specification for high-level module reuse and maintainability.
Exception: Object creation is a violation of the "open-closed" principle and the dependency reversal principle, but through the factory model, it can be a good solution to the object creation process of dependency reversal problem.
3.2 relationship
The principle of "open-close" and dependence reversal is the relationship between the goal and the means. If the principle of opening is the goal, reliance on the reversal principle is the means to reach the "open and close" principle. If the best "open and close" principle is to be achieved, it is necessary to obey the principle of dependency reversal and the principle of dependence reversal is the best norm of "abstraction".
The principle of substitution on the Richter scale is based on the reversal principle, which is an important supplement to the principle of the substitution of the Richter.
3.3 The type of coupling (or dependency) relationship:
0 coupling (Nil coupling) Relationship: Two classes do not have a coupling relationship.
Specific coupling (concrete coupling) Relationship: Occurs between two specific (instantiated) classes, caused by a class to a direct reference to another specific class.
Abstract coupling relationship: Occurs between a concrete class and an abstract class (or interface), allowing for maximum flexibility between the two classes that must have a relationship.
3.3.1 How to grasp coupling
We should avoid implementing inheritance as much as possible for the following reasons:
1) Loss of flexibility, the use of specific classes will bring trouble to the underlying changes.
2) coupling problem, coupling means that two entities depend on each other for a measure. Programmers make decisions that affect coupling every day (consciously or unconsciously): class coupling, API coupling, application coupling, and so on. In an extended inheritance implementation system, derived classes are very tightly coupled to the base class, and this tight connection may be undesirable. For example, B extends A, when B does not use all the methods in a, then the method called by B may produce an error!
We must evaluate the coupling objectively, and the system cannot always be loosely coupled, so there is no way to do anything.
3.3.2 What is the basis of our decision on the degree of coupling ?
Simply put, the degree of coupling is determined according to the stability of the requirement. For the requirements of high stability, not prone to change, we can fully design the various types of tightly coupled (although we discuss the coupling between classes, but in fact, the function block, module, the coupling between the package is the same), because it can improve efficiency, And we can also use some better techniques to improve efficiency or simplify code, such as the internal class technology in C #. However, if the demand is very likely to change, we need to fully consider the coupling between classes, we can come up with a variety of ways to reduce the degree of coupling, but summed up, it is not only to increase the level of abstraction to isolate different classes, this level of abstraction can be abstract classes, specific classes, can also be interfaces, Or a group of classes. We can summarize the idea of reducing coupling in a sentence: "Programming for interfaces, not for implementation." ”
When we encode, we will leave our fingerprints, such as the number of public, the format of the code, and so on. We can evaluate the risk of re-building the code by coupling metrics. Because rebuilding is actually a form of maintaining coding, the hassles that are encountered during maintenance are also encountered when rebuilding. We know that after rebuilding, most of the most common random bugs are caused by improper coupling.
The greater the instability factor, the greater the coupling.
The instability factor of a class = number of dependent classes/number of dependent classes
Number of dependent classes = Sum of the number of other classes compiled at the time the class was compiled
3.3.3 How to split large systems into small systems
One way to solve this problem is to combine many classes into a higher-level unit to form a collection of high cohesion, low-coupling classes that we should focus on in our design process!
The goal of coupling is to maintain the unidirectional nature of dependencies, and sometimes we also need to use bad coupling. In this case, care should be taken to record the reasons for this to help users of the code later understand the real reason for using coupling.
How does 3.4 rely on inversion?
Coupling in an abstract way is the key to relying on the reversal principle. Abstract coupling relationships always involve concrete classes inheriting from abstract classes, and it is necessary to ensure that any reference to the base class can be converted to its subclasses, so the Richter substitution principle is based on the principle of reversal.
Although coupling at the level of abstraction is flexible, it also brings additional complexity, and if the likelihood of a specific class change is very small, then the benefits of an abstract coupling can be very limited, which can be better with concrete coupling.
Hierarchical: All well-structured object-oriented architectures have a clear hierarchical definition, with each level providing a cohesive set of services to the outside through a well-defined, controlled interface.
Dependent on abstraction: the recommendation does not depend on a specific class, that is, all dependencies in a program should terminate in an abstract class or interface. Try to do the following:
1. Any variable should not hold a pointer or reference to a specific class.
2. No class should derive from a specific class.
3. No method should overwrite an already implemented method in any of its base classes.
Advantages and disadvantages of 3.5 dependency reversal principle
The reliance reversal principle, while powerful, is the least likely to be achieved. Because of dependency inversion, object creation is likely to use object factories to avoid direct references to specific classes, and the use of this principle may result in a large number of classes, and for engineers unfamiliar with object-oriented technology, maintaining such a system requires a good understanding of object-oriented design.
The dependency reversal principle assumes that all specific classes are subject to change, and this is not always true. There are some specific classes that may be fairly stable and will not change, and an application that uses this specific class instance can rely entirely on this specific type, without having to create an abstract type for this.
Iv. Synthesis/ Aggregation multiplexing principle ( composite/aggregate Reuse Principle or CARP )
4.1 Concept
Definition: Use some existing objects inside a new object to make them part of the new object, and the new objects are used to reuse the objects by delegating them to them.
The synthesis/aggregation should be used first, and the synthesis/aggregation makes the system flexible, followed by the inheritance to achieve the purpose of reuse. When using inheritance, we should strictly follow the principle of the Richter substitution. Effective use of inheritance can help to understand problems, reduce complexity, and misuse of inheritance can increase system build-up, maintenance difficulties, and system complexity.
If the two classes are "has-a" the relationship should use the composition, aggregation, and if the "is-a" relationship can use inheritance. "Is-a" is defined in strict taxonomic sense, meaning that one class is the "one" of another. and "Has-a" is different, it means that a role has a certain responsibility.
4.2 what is synthesis? What is aggregation?
Synthesis (composition) and aggregation (Aggregation) are a special kind of association (association).
aggregations represent the whole and part of the relationship, which means "owning". such as Mercedes-Benz S360 car, the relationship between Mercedes-Benz S360 engine, Mercedes-Benz S360 tires is an aggregation relationship, leaving the Mercedes-Benz S360 car, engine, tires lost the meaning of existence. In design, aggregation should not occur frequently, which increases the coupling of the design.
Synthesis is a stronger "own", part-and-whole life cycle. The new objects of the composition completely dominate their constituent parts, including their creation and annihilation. A composition object of a composition relationship cannot be shared with another composition relationship.
In other words, a composition is an aggregation of values (Aggregation by value), whereas a general aggregation is a referenced aggregation (Aggregation by Reference).
Understand the composition and aggregation relationships, and then to understand the composition/aggregation principle should be clear, to avoid in the system design, the inheritance level of a class more than 3 layers, you need to consider refactoring code, or redesign the structure. The best approach, of course, is to consider the use of synthetic/aggregation principles.
advantages and disadvantages of 4.3 through synthesis/ polymerization
Advantages:
1) The only way to access an ingredient object from a new object is through the interface of the Component object.
2) This reuse is a black-box reuse because the inner details of the constituent objects are invisible to the new object.
3) This multiplexing supports packaging.
4) This multiplexing requires less reliance.
5) Each new class can focus on one task.
6) This multiplexing can be performed dynamically during runtime, and new objects can dynamically reference objects of the same type as the constituent objects.
7) As a means of reuse can be applied to almost any environment.
disadvantage: There will be more objects in the system to be managed.
4.4 Advantages and disadvantages of using inheritance for reuse
Advantages:
1) The new implementation is easier because most of the functionality of the superclass can be automatically entered into subclasses through inherited relationships.
2) It is easier to modify and extend inherited implementations.
Disadvantages :
1) Inheritance multiplexing destroys encapsulation, because inheritance exposes the implementation details of the superclass to subclasses. Because the inner details of the superclass are often transparent to the subclass, this reuse is transparent multiplexing, also known as "white box" multiplexing.
2) If the superclass changes, then the implementation of the subclass will have to change.
3) implementations inherited from the superclass are static and cannot be changed within the runtime, without sufficient flexibility.
4) Inheritance can only be used in a limited environment.
Five, Dimitri Law ( Law of Demeter , LoD )
5.1 Overview
Definition: A software entity should interact with as few interactions as possible with other entities.
This way, when a module is modified, it will affect the other modules as little as possible. Scaling is relatively easy.
This is a limitation of communication between software entities. It requires limiting the width and depth of communication between software entities.
Other representations of the law of 5.2 Dimitri
1) only communicate with your direct friends.
2) Don't talk to "strangers".
3) Each software unit has only minimal knowledge of the other units, and is limited to the software units that are closely related to the unit.
The Dimitri law in the narrow sense of 5.3
If two classes do not have to communicate directly with each other, then these two classes should not have a direct interaction. If one of the classes needs to invoke a method of another class, the call can be forwarded through a third party.
Determination of the circle of Friends, "friend" condition:
1) Current object itself (this)
2) An object that is passed into the current object method as a parameter
3) object directly referenced by the instance variable of the current object
4) instance variables for the current object if it's a cluster, then the elements in the cluster are all friends.
5) objects created by the current object
Any object that satisfies one of the above conditions is the "friend" of the current object, or "stranger".
Cons: There will be a lot of small methods in the system, scattered in all corners of the system.
Complementary to the dependency reversal principle.
5.4 The shortcomings of the narrow Dimitri Law:
A large number of small methods are created in the system, and these methods simply transmit indirect calls, regardless of the business logic of the system.
Following the Dimitri rule between classes is a simplification of the local design of a system, since each part is not directly associated with objects of long distance. However, this also causes the communication efficiency between different modules of the system to be reduced, and the system can not be easily coordinated between the different modules.
5.5 Dimitri Law and design pattern
Façade (appearance) mode and mediator (mediator) mode are actually the specific application of the Dimitri Law.
The Dimitri rule of 5.6 generalized
The main purpose of the Dimitri Law is to control the overload of information. When applying the Dimitri rule to system design, pay attention to the following points:
1) in the division of classes, a class with weakly coupled should be created.
2) in the class structure design, each class should minimize the member's access rights.
3) in the design of the class, whenever possible, a class should be designed to be invariant class.
4) on references to other classes, an object's reference to its object should be minimized.
The embodiment of 5.7 generalized Dimitri Law in the design of class
1) Prioritize the setting of a class to an immutable class
2) Minimize access to a class
3) Use serializable sparingly
4) Minimize access to members
5) Replace C Struct
The Dimitri rule is also called the least-knowledge principle (Least knowledge principle or abbreviated as LKP), meaning that an object should have as little understanding of other objects as possible.
5.8 How to implement Dimitri Law
The main purpose of Dimitri Law is to control the overload of information, in the application of the system design should pay attention to the following points:
1) in the division of classes, a class with weakly coupled should be created. The weaker the coupling between classes, the more beneficial it is to reuse.
2) in the class structure design, each class should minimize the member's access rights. A class should not public its own property, but should provide a way to give value and assignment to the outside world to access its properties indirectly.
3) in the design of the class, whenever possible, a class should be designed to be invariant class.
4) on references to other objects, a class's reference to other objects should be minimized.
Six, Interface Isolation principle (I nterface segregation Principle, ISP )
6.1 concept
Interface Isolation principle: Using multiple specialized interfaces is better than using a single total interface. That is, the dependency of a class on another class should be based on the smallest interface.
The "interface" here often has two different meanings: one refers to a set of method features that a type has, is merely a logical abstraction, and the other refers to a specific "interface" definition of a language, with a strict definition and structure. such as the C # language inside the interface structure. For both of these different meanings, the way the ISP is expressed and what it means is different. (one of the types mentioned above can be understood as a class, we define a class, which defines a new type)
This is a logical concept when we understand the "interface" as a collection of features of all the methods provided by a class. The partitioning of interfaces directly leads to the division of types. Here, we can understand the interface as a role, an interface just represents a role, each role has its own specific interface, this principle can be called "role segregation principle."
If the "interface" is understood as a narrow language-specific interface, then the ISP expression means that the different clients, the same role to provide a wide range of interfaces, that is, custom services, personalized services. is simply to provide the behavior that the client needs, and the behavior that the client does not need is hidden.
The client should be provided with as small a separate interface as possible, rather than providing a large total interface.
This is also a limitation of communication between software entities. But it limits the width of the communication, which means the communication should be as narrow as possible.
Following the Dimitri rule and the interface isolation principle, the modified pressure is not propagated to other objects when a software system function is extended.
6.2 How to implement the principle of interface isolation
Users should not be forced to rely on methods that they do not use.
1, the use of delegated separation interface.
2, the use of multi-inheritance separation interface.
Vii. single principle of responsibility (SRP)
Single responsibility principle (SRP), in the case of a class, there should be only one cause for it to change. In other words, do not put together responsibilities that vary in reason, because different changes can affect irrelevant responsibilities. More popular point is that you should not take care of the things you do not care, the management of their own things can be, meddling in their own harm to others.
In software design, if a class takes on too much responsibility, it is tantamount to these responsibilities being coupled, and a change in responsibility may weaken and inhibit the ability of this class to perform other duties. This coupling leads to fragile designs that can be subjected to unexpected damage when the changes occur.
The real thing about software design is to discover responsibilities and separate those responsibilities from each other. If there is more than one motive to change a class, then the class has a redundant responsibility, and the separation of duties of the class should be considered.
Summary
When we design an object-oriented system, we can not deliberately consider which design patterns to use, but be sure to follow these design principles as much as possible. In doing so, even if the design experience is not enough, it is relatively easy to design a scalable system, and may naturally implement some patterns. This situation, I am afraid, is an ideal design.
Object-Oriented design principles