Preface

“ You don't need a gun to kill a programmer , Three changes in demand ”, Although this is a joke , But it also describes the importance of software maintainability from the side

Famous software master Robert C.Martin Think of a maintainability (Maintainability) Lower software design , Usually due to the following 4 A cause of

1) Too rigid (Rigidity): The design is hard to modify

2) Too fragile (Fragility): Design is vulnerable to destruction ( When it needs to be changed , Easy to pull a hair and move the whole body , The code that should not be affected is also forced to be destroyed )

3) Firmness (Immobility): Low reuse rate ( When you want to use some functions, you will find that some code in it is not what he wants , When you want to get rid of this code , It's hard to get rid of , The reason is that the code coupling is too high )

4) The viscosity is too high (Viscosity): It's hard to do the right thing ( I want to modify some code during maintenance , But there's no way to change it , The reason is that the viscosity is too high )

Master of software engineering and modeling PeterCoad Think , A good system design should have the following three characteristics :

1) Extensibility (Extendibility)

2) flexibility (Flexibility)

3) Insertability (Pluggability)

Object oriented design principles and design patterns are also reasonable reconfiguration of the system , Refactoring is based on not changing the existing functions of the software , Improve software quality by adjusting code 、 performance , Make the design pattern and architecture of the program more reasonable , Improve the expansibility and maintainability of the software .

The seven principles do not exist in isolation , They depend on each other , Complement each other .

1. Principle of single responsibility ( Importance 4 star )

summary :

Class has a single responsibility , You can't put too many responsibilities in one class

Definition :

An object should contain only a single responsibility , And the responsibility is completely encapsulated in a class ( Another definition is for a class , There should be only one cause for it to change .)

Principle analysis :

1) The more responsibilities a class takes on , The less likely it is to be reused , And if a class has too many responsibilities , It's like coupling these responsibilities , When one of the responsibilities changes , May affect the operation of other duties .

2) The responsibilities of a class mainly include two aspects : Data responsibility and behavior responsibility , Data responsibility is embodied by its attributes , And the responsibility of behavior is embodied by its methods .( Focus on behavioral responsibility )

3) The single responsibility principle is to achieve high cohesion , Guidelines for low coupling , It can be found in many ways of code refactoring , It's the simplest and most difficult principle , It needs the actual person to discover the different responsibilities of the class and separate them , The multiple responsibilities of discovery class require designers to have strong analysis and design ability and relevant reconstruction experience .

Example is given to illustrate :

Login function through the following Login Class (Login) Realization :

 Seven principles of object orientation , How many do you know? ?

init Method is to initialize the login page

display The method is to display the login interface

validate The method is to verify the validity of the login account and password ( Syntax validation on the page )

getConnertion and findUser Methods to verify the validity of account and password

main The way to do this is through the program portal

design analysis :

The first three are page methods , The latter two are business approaches , The last one is the entry to the program , Several methods belong to different aspects , It shows that there is a lot of responsibility . A class should have only one change point , Should do their own job , You can't change a class for some reason , On the contrary, it shows that this class has too many responsibilities . For example, if the page changes ,init Methods need to be changed ; Another example is that the validation rules change ,validate Methods need to be changed, etc ; These are the changing points . So Login It doesn't conform to the principle of single responsibility ( So , We can judge whether the principle of single responsibility is consistent with the change point ).

Now we use the principle of single responsibility to reconstruct it .

 Seven principles of object orientation , How many do you know? ?

design analysis :

take Login Break it down into MainClass( Responsible for the entry of the program )LoginForm( Interface view ),UserDAO( Classes that interact with user objects ),DBUtil( The class responsible for connecting to the database ) These four classes . We can see that these four are different points of change , They're all irrelevant , For example , If the interface needs to change , We just need to put LoginForm Methods in class , There is no need to change the methods of other classes , Therefore, such decomposition is really in line with the principle of single responsibility .

summary :

If we follow the principle of single responsibility , We can put a complex ( Or too much responsibility ) According to the idea of business logic, the class of is decomposed , Split into such a class with high cohesion and low coupling , The ultimate goal is to improve software ( Or this class ) The maintainability of ( Or reusability ), So the idea is very simple , But it's hard when we do it . From here we should also be able to see that structure is very important . So we consciously approach this aspect in our usual practice , We must follow this principle seriously .

2. Opening and closing principle ( Importance 5 star )

summary :

Software implementation is open to extension , But the changes are closed , That is to extend the function of a software entity without modifying it

Definition :

That is to say, when designing a module , This module should be extended without modification , That is to change the behavior of this module without modifying the source code .

Principle analysis :

1) The principle of opening and closing is Bertand Meyer On 1988 Put forward in , It's one of the most important principles in object-oriented design .

2) In the definition of opening and closing principle , Software entity can refer to a software module 、 A local structure of multiple classes or an independent class .

3) Abstraction is the key to the open close principle .

notes :

Abstraction refers to the extraction of common things from one or more classes .

The best thing about abstraction is that it's stable 、 reliable ‘ Not easy to change .

4) The open close principle can also be adopted in a more specific way “ The encapsulation principle for variability “ To describe , The principle of variability requires finding and encapsulating the variables of the system .

Example is given to illustrate :

A graphical interface system provides buttons of various shapes , The client code can be programmed for these buttons , Users may change their requirements and require different buttons , The original design is shown in the picture :

 Seven principles of object orientation , How many do you know? ?

design analysis :

Now the customer wants to make a login interface , Want to make a round button , stay LoginForm The interface contains a CircleButton class , Provide a display Method . But after a while , The customer wants to program a circular button into a rectangular button , Only take button The interface changes to a circular interface . If it is reasonable according to our usual thinking , But if you follow the principle of opening and closing , It's a design that goes against the principle of opening and closing , It's not a good design .

Use the open close principle to reconstruct it :

 Seven principles of object orientation , How many do you know? ?

design analysis :

I added one here AbstactButton The abstract class of , Next, we will implement the two classes .LoginFrom Class button The type changes , There was a specific type before it changed to AbstarctButton class . It can be transformed through polymorphism . It proves that abstraction is the key to realize the open close principle .

summary :

The idea of the open close principle is to add a stable abstract class to the unstable class , Then extract the points you need from specific classes and put them into third-party classes , Enhance code stability . So the key to the open and close principle is abstract methods .

The open close principle is the standard to measure the quality of a code .

3. Richter's principle of substitution ( Importance 4 star )

summary :

In software system , Where a base class object can be accepted, a subclass object can be accepted

Definition :

If for each type S The object of o1, All of them are of type T The object of o2, So that T It's defined as a program P In all objects o1 Are replaced with o2 when , Program P There's no change in the behavior of , So the type S It's the type T Subtypes of .

( All places used for base classes must be able to Transparently Objects that use their subclasses )

Principle analysis :

1) Richter's principle of substitution consists of 2008 Turing prize winner in 、 The first female doctor of Computer Science in the United States 、 Professor of MIT Barbara Liskov And Carnegie . Mellon University Jeannette Wing Professor Yu 1994 in .

2) The principle of Richter's substitution can be expressed as : stay If base class objects can be used in software , Then you must be able to use its subclass object .( notes ) Replace the base class with its subclass , The program will not produce any errors or exceptions , The reverse is not true , If a software entity uses a subclass , So it doesn't have to be able to use base classes .

3) Richter's replacement principle is one of the important ways of real-time open close principle , Because where base class objects are used, subclass objects can be used , therefore Try to use base class types to define objects in your program , At run time, it's determining its subclass type , Replace the superclass object with a subclass object .

Example is given to illustrate :

A system needs to realize the important data ( Such as user password ) Encryption processing of , In the data operation class (DataOperator) You need to call the encryption algorithm defined in the encryption class , The system provides two different encryption classes ,CipherA and CipherB, They implement different encryption methods , stay DataOperator You can choose one of them to implement the encryption operation . As shown in the figure :

 Seven principles of object orientation , How many do you know? ?

Client The client side. (main Method )

DataOperator Data operation class

CipherA and CipherB Two encryption classes , Encrypt in different ways

 Seven principles of object orientation , How many do you know? ?

design analysis :

If you need to change an encryption algorithm class or add and use a new encryption algorithm class , Such as the CipherA Change it to CiherB, You need to modify the customer class Client And data manipulation class DataOperator Source code , Against the principle of opening and closing .

as a result of DataOperator The method in it directly refers to two encryption classes , Too close , Too high coupling .

It is reconstructed by using the Ritz substitution principle :

 Seven principles of object orientation , How many do you know? ?

design analysis :

1. The original unrelated CipherA and CipherB The two classes become inherited ( Because it's all for plaintext , Get the ciphertext . It's the same thing , It's just different ) take CipherA Parent class , hold CipherB As a subclass .

2. take DataOperator The variables in the class become CipherA The base class .

3. Put the extra set Methods to remove , As long as the parent class . The variables passed in are also base classes .

We put the algorithm that the client wants to use outside the client xml In the document , If you want to change it, just change the configuration file , If the extension directly adds subclasses .

 Seven principles of object orientation , How many do you know? ?

summary :

If there's a lot of if-else perhaps case If this kind of choice structure , It shows that the code needs to be optimized by using Richter's substitution principle , Abstracting different situations , Extract public things and create a parent class , Let subclasses inherit , When different functions need to be implemented after inheritance , You need to use @Override Rewriting methods ( In the form of polymorphism )

If the program follows the Ritz substitution principle , Inheritance can be a powerful tool for reducing complexity , Because it allows programmers to focus on the general characteristics of objects without worrying about the details . If programmers have to constantly think about the semantic gap between the implementations of different derived classes , Inheritance only adds complexity .

4. The principle of Dependence Inversion ( Importance 5 star )

summary :

To program against the abstraction layer , Instead of programming for specific classes

Definition :

High level modules should not rely on low level modules , They should all be Dependency abstraction .

Abstractions should not depend on details , Details should depend on abstraction .

Be careful :

To program for an interface , Don't program for implementation .

Principle analysis :

1) Well structured object-oriented architectures have clear hierarchical definitions , Each level is well defined by one , Controlled interfaces provide a cohesive set of services to the outside world .

 Seven principles of object orientation , How many do you know? ?

  • high-level Policy Layer-> low Mechanism Layer-> low UtilityLayer, It seems normal ( If the name of the underlying property or method changes , Does it need to change at the top , So there is a problem . The code is fragile )

  • Policy Layer For dependent 2 individual layer All changes are sensitive .

2) The principle of dependency inversion is Robert C.Martin stay 1996 Years for 《C++Reporter》 The column I wrote Engineering Notebook The third part of , Later he joined him in 2002 A classic published in 《Agile Software Development,Princiles,Patterns,and Practices》 in

3) Simply speaking , The principle of dependency inversion means : Code depends on abstract classes , Don't rely on specific classes ; To program against an interface or abstract class , Instead of programming for specific classes .

rely on ( coupling ) Relationship :(1. For example, I have one now A This class , then A call B The method inside , So this time is A rely on B.2.A Inherited B, This is the time A It's also dependence B) all A and B Where relationships happen, they're all dependencies .

Better description : Don't rely on concrete classes that are easy to change . If you want to inherit a class , Inherit from an abstract class . If you want to hold a reference to a class , From an abstract class reference . If you want to call a function , Call from an abstract function .

4) The key to realize the open close principle is abstraction , And from abstraction to materialization , if Open close principle is the goal of object-oriented design , that The principle of dependency inversion is the main means of object-oriented design .

5) One of the common implementations of the dependency inversion principle is Using abstract classes in code , And put the concrete class in the configuration file .

  • Put the abstraction into the code , Put the details into the metadata ”( Abstraction is stable , Unalterable . Metadata is a configuration file , You can modify )
  • Put Abstractions in Code,Details in Metadata(《 The way of programmer training : The Pragmatic Programmer 》 What the book says )

6) The dependency inversion principle is used to decouple , Make the coupling between the code become lower and lower , To achieve the purpose of understanding coupling .

  • Coupling between classes

    ( High cohesion means that a software module is composed of highly relevant code , Only one task , That is to say, the principle of single responsibility .
    Low coupling means that each module can complete a specific sub function independently as much as possible .)

    • Zero coupling

    If there is no coupling between two classes, it is zero coupling , But it's just what we hope for , It's hard to achieve .

    • Specific coupling relationship

    It happens in two specific classes ( Instantiatable ) Between , The coupling relationship caused by the direct application of one class to another is the concrete coupling relationship .

    • Abstract coupling

    Occurs in a concrete class and an abstract class ( Or interface ) Between , The coupling that allows the greatest flexibility between two required classes is abstract coupling .( for instance A Depend on B,B It's an interface . This is the abstract coupling relationship )

7) Dependency inversion requires clients to rely on abstract coupling , Coupling in an abstract way is the key to the dependency inversion principle .

​ The client often calls the server , So the client depends on the server . But according to the principle of inversion of dependence , Abstract coupling is recommended , Rely on abstract classes or methods .

 Seven principles of object orientation , How many do you know? ?

Add a layer of abstract interface in two concrete implementations , Make it stable .( The top layer relies on interfaces , Each of the following layers implements interfaces , In this way, both the upper layer and the lower layer depend on the interface )

8) Dependency injection :

A Rely on abstract C,B It also depends on the abstract C. At this time, we need specific code implementation B( This is dependency injection ).

  • Tectonic injection : Inject instance variables through constructors .
  • Set value injection : adopt Setter Method injection instance variable .
  • Interface injection : Injecting instance variables through interface methods .

    Example is given to illustrate :

    A system provides a data conversion module , You can convert data from different data sources into multiple formats , If you can convert data from a database 、 You can also convert data from text files , The converted format is also XML file 、 It can also be XLS Documents, etc. . The design according to the requirements is as follows :

 Seven principles of object orientation , How many do you know? ?

Because of the change in demand , The system may require Add new data sources or new file formats , Every time you add a new type of data source or a new type of file format , Customer class MainClass All need to change the source code , To use the new class , But it violates the opening and closing principle .

Now we use the dependency inversion principle to reconstruct it

 Seven principles of object orientation , How many do you know? ?

Abstract two concrete methods , At the same time, two methods of text conversion are abstracted . And then let MainClass Dependent interface , Put the changes on the configuration file . This is in line with the principle of dependency inversion , The problem of extension has been solved .

5. Interface isolation principle ( Importance 2 star )

summary :

Use multiple specialized interfaces to replace a unified interface

Definition :

  • The client should not rely on interfaces it does not need .
  • Or once an interface is too large , You need to break it up into smaller interfaces , Clients using this interface only need to know the methods related to it .

Principle analysis :

1) The interface isolation principle refers to the use of multiple specialized interfaces , Instead of using a single master interface . Each interface should take on a relatively independent role , No less , Don't do what you shouldn't do , Do whatever you have to do .

  • An interface represents only one role , Each character has its own unique interface , This principle can be called “ The principle of segregation of roles ”.
  • The interface only provides the behavior required by the client , That is, the method required , The unwanted behavior of the client is hidden , The client should be provided with a separate interface as small as possible , Instead of offering big lessons .

2) When splitting an interface using the interface isolation principle , First of all, we must satisfy Principle of single responsibility , Define a set of related operations in an interface , And on the premise of satisfying high cohesion , The fewer methods in the interface, the better .

3) It can be used in system design Custom service The way , namely Provide different interfaces for different clients , Only provide the behavior that users need , And hide behaviors that users don't need .

Example is given to illustrate :

The developer designed the interface for the customer data display module of a certain system as shown in the figure

 Seven principles of object orientation , How many do you know? ?

dataRead() Used to read data from a file

transfromToXML() Used to convert data into XML Format

createChart() Used to create charts ,

displayChart() Used to display charts

createReport() Used to create a text report

dislayReport() Used to display text reports

client Interface , The interface calls the methods in the interface , Method and then the specific implementation . Although this design also realizes the required function , And it also satisfies the principle of dependence inversion , But it's not perfect .

  • If the data format is CML, There is no need to convert , What do I do
  • If you just need to create and display images , What should I do
    • So the first two and the last two become a burden of interface classes , It will not be on
  1. The problem is : Interfaces take on too much responsibility : The implementation class of this interface is very large , Implementation classes need to implement all methods of the interface , Poor flexibility , If there are a lot of empty methods , Will lead to a lot of useless code in the system , Impact code quality ;
  2. Because the client programming for large interfaces , Will be in To some extent, it breaks the encapsulation of the program , The client sees methods that should not be seen , There is no custom interface for the client .
  3. Therefore need Interface isolation principle and single responsibility principle are reconstructed . Encapsulate some of these methods in different small interfaces , Make sure each interface is easy to use , And all assume a single role , There is only one client in each interface ( Such as modules or classes ) The method needed is .( This kind of problem requires us to learn how to split , Split large interfaces into small ones , This makes us need to consider .)

Now we use the principle of interface isolation to reconstruct it :

 Seven principles of object orientation , How many do you know? ?

Split each function , Each class has a separate implementation method . This optimizes the code .

6. Synthetic multiplexing principle ( Importance 4 star )

summary :

Composition and aggregation class association should be used as much as possible in the system , Use as little or no inheritance as possible

The principle of composite reuse is also called combination / Principle of aggregation and reuse .

Definition :

Try to use object combinations , Instead of inheritance to achieve reuse .( An important feature of object-oriented is to reuse some code as much as possible )

Principle analysis :

1) The principle of composite reuse refers to a new object through association ( Including combination relationship and aggregation relationship ) To use some existing objects , Make it part of a new object ; A new object can reuse its existing functions by delegating and calling the methods of existing objects . in short : Try to use combinations / Aggregate relationship , Use less inheritance .

2) In object-oriented design , There are two basic ways to reuse existing designs and implementations in different environments , By combining / To aggregate or inherit .

  • Inheritance reuse : Implement a simple , extensible . Destroy the encapsulation of the system ( Subclasses inherit methods or properties that the parent class can inherit , Then it is equivalent to that the subclass knows the structure or internal implementation function of the parent class , So it breaks the encapsulation ); The implementation inherited from the base class is static , It's impossible to change at run time , Not enough flexibility ( You can only change the source code to change the function , You can't change it while it's running .); It can only be used in a limited environment .(“ White box ” Reuse )
  • Combine / Aggregate reuse : The coupling is relatively low , Selectively call the operation of the member object ; It can be done dynamically at runtime .(“ black box ” Reuse )(A call B Class methods do not know B The structure of the black box is reuse )

3) Combine / Aggregation can Make the system more flexible , Between classes Reduced coupling , Changes in one class have relatively little impact on other classes , So in general The preferred combination is / Aggregation for reuse ; Second, consider inheritance , When using inheritance , We need to strictly follow the Ritz substitution principle , Using inheritance effectively will help to understand the problem , Reduce complexity , The abuse of inheritance will increase the complexity of system construction and maintenance , Therefore need Use inheritance reuse carefully .

Example is given to illustrate :

Some teaching management system database access class design as shown in the figure :

 Seven principles of object orientation , How many do you know? ?

  • If you need to change the database connection mode , If the original use of JDBC Connect to database , Now use database connection pool connection , It needs to be modified DBUtil Class source code .

  • If StudentDAO use JDBC Connect , however TeacherDAO Using connection pool connection , You need to add a new DBUtil class , And modify it StudentDAO or TeacherDAO Source code , Make it inherit the new database connection class , This would violate the open close principle , Poor system scalability .

Now we use the principle of composite reuse to reconstruct it .

 Seven principles of object orientation , How many do you know? ?

7. Dimitar's law ( Importance 3 star )

summary :

The fewer references a software entity has to other entities, the better , Or if two classes don't have to communicate directly with each other , Then there should be no direct interaction between the two classes , It's indirect interaction by introducing a third party

Definition :

1) Do not mix “ A stranger ” speak

2) Only communicate with your direct friends

3) Every software unit has the least knowledge of other units , And it is limited to those software units closely related to this kind of units

Principle analysis :

1) Dimitri's law is also called the law of least knowledge .

2) Dimitar's law comes from 1987 In the autumn of, there was a new university named “Demeter” Research projects of

3) In short , Dimitar's law is A software entity should interact as little as possible with other entities . such , When a module is modified , It will affect other modules as little as possible , Expansion will be relatively easy , This is between software entities Restrictions on Communication , He wants to restrict communication between software entities Width and depth .( Width refers to the area involved , Depth is the number of subclasses involved )

4) In Dimitar's law , For an object , Its friends include the following :

  • The current object itself (this)
  • The object passed into the current object method as a parameter

  • Member object of current object

  • If the member of the current object is a collection , Then all the elements in the collection are friends

  • The object created by the current object

 Seven principles of object orientation , How many do you know? ?

5) Any object , If one of the above conditions is met , It's the current object “ friend ”, Otherwise, it would be “ A stranger "

6) Ground mitt's law can be divided into narrow sense law and broad sense law . In the narrow sense of Dimiter's law , If two classes don't have to communicate directly with each other , Then the two classes should not interact directly , If one class needs to call a method of the other class , You can forward this call through a third party .

 Seven principles of object orientation , How many do you know? ?

Above picture Object A and Object B It's an interdependent relationship A The parameter type passed in a method is Object B type , And then you can communicate , Now? A Want to call C The method inside , The first way is A and C It's directly related to ( But we don't advocate , Advocate indirect relationship ) The second way is A call B,B call C, This is the indirect relationship .

  • The law of Dimiter in the narrow sense : Sure Reduce coupling between classes , But it will add a lot of small methods to the system and scatter them all over the system , He can simplify the local design of a box system , Because each one is not directly related to distant objects , But it will also Cause the characteristic efficiency between different modules of the system to reduce , It makes the different modules of the system difficult to coordinate .
  • The general law of Dimiter : It refers to the information flow between objects 、 Control of flow direction and the impact of information , It's mainly about The control of information hiding . Information hiding can decouple the subsystems , To allow them to be developed independently 、 Optimize 、 Use and modify , At the same time, it can promote the reuse of software , Because every module It doesn't depend on other modules , So each module can be used independently in other places . The larger a system is , The more important it is to hide information , The more important information hiding is, the more obvious it is .

7) The main use of Dimitri's law is Control information overload

  • In the division of classes , We should try our best to Create loosely coupled classes , The lower the coupling between classes , The more beneficial it is to reuse , Once a loosely coupled class is modified , Classes that don't associate cause too much noise and ;
  • On the structure design of class , Every class should be Minimize access to member variables and member functions ;
  • On the design of class , Whenever possible , A type should be designed as an immutable class (final modification );
  • On references to other classes , One object's reference to other objects should be minimized ( If it doesn't matter, it doesn't matter ).

Example is given to illustrate :

A system interface class ( Such as Form1、Form2 Such as ) And data access class ( Such as DAO1、DAO2 Such as ) The call relationship between is more complex , As shown in the figure :

 Seven principles of object orientation , How many do you know? ?

analysis :

If the data template class DAO1 change ,Form1 and Form2 All need to change . So this coupling relationship needs to be decoupled .

Now we use Dimitri's law to reconstruct it .

 Seven principles of object orientation , How many do you know? ?

analysis :

Add a middle layer between the system interface layer and the data access layer , So that there is no direct communication between the two , This greatly decouples . It doesn't move the whole body with one hair . Let's say ( If DAO1 Change , Not to Form1 To change , Maybe it just needs to change Controller1 Some of the methods in it ).

Design thinking and summary

1) For software systems , In support of Maintainability At the same time , We need to improve the performance of the system Reusability .

2) Software reuse can improve the efficiency of software development , Improve software quality , Save development costs , Proper reuse can also improve the maintainability of the system .

3) The principle of single responsibility requires that in software systems , A class is only responsible for the corresponding responsibilities in a functional area .

4) The open close principle requires that a software entity should be open to extensions , Turn off for changes , That is to extend the behavior of a system without modifying the source code .

5) Richter's replacement principle can be expressed as if base class objects can be used in software , Then you must be able to use its subclass object .

6) The principle of dependency inversion requires that abstraction should not rely on details , Details should depend on abstraction ; To program for an interface , Don't program for implementation .

7) The interface isolation principle requires that the client should not rely on interfaces it does not need , That is, some large interfaces are refined into some small interfaces for clients to use .

8) The principle of composite reuse requires that object composition be used as much as possible when reusing , Instead of using inheritance .

9) Demeter's law requires that a software entity should interact as little as possible with other entities .

 Seven principles of object orientation , How many do you know? ?

Object oriented design does two things , One is the design of classes , The other is the design of the relationship between classes . The main purpose is to make the code highly cohesive , The purpose of low coupling .

 Seven principles of object orientation , How many do you know? ?

end :

This article has basically finished the seven principles of object-oriented , I'd like to say a few more words here , Object oriented has more than seven principles , We're just going to talk about the seven important ones .