Java development principles (seven)

Reprinted from: https://blog.csdn.net/u011288271/article/details/52497602

I have seen a very interesting statement about Java: Java has six mental methods and 23 martial arts moves.

They are the six principles of Java design patterns and the 23 commonly used design patterns.

This article is a compilation of six principles. (The last one is Hamlet)

1. The Open Close Principle
defines that a software entity such as a class, module, and function should be open for extension and closed for modification.
    The open-closed principle means that when you design, you should always consider it, try to make this class good enough, and don't modify it after writing it. If new requirements come, we add some classes and it's done. The original The code doesn't move if it doesn't move. This principle has two properties, one says "open for extension" and the other says "closed for change". In the face of demand, changes to the program are made by adding new code, not changing existing code. This is the spirit of the "Open-Closed Principle". For
    example, at the beginning, the requirement was only to write an addition program, and soon after it was completed in the client class, the change did not occur at this time, and a subtraction function was required to be added. At this time, the added function will be found. It is necessary to modify the original class, which violates the open-closed principle, so you should consider refactoring the program, adding an abstract operation class, and isolating the specific addition, subtraction and The client is coupled, the requirements can still be met, and it can also cope with changes. At this time, if you need to add multiplication and division functions, you do not need to change the client and addition and subtraction classes, but add multiplication and division subclasses.
Absolute modification closure is impossible. No matter how 'closed' the module is, there will be some changes that cannot be closed. Since it is impossible to completely close, the designer must make a decision on which changes the module he designs should be closed to. choose. He must first guess the most likely kinds of changes, and then construct abstractions to isolate those changes. When we originally wrote our code, we assumed that changes would not happen, and when they did, we created abstractions to isolate future changes of the same kind.
     What we want is to know about possible changes soon after development begins, and the longer you wait to find out about possible changes, the more difficult it is to create the correct abstraction. The open-closed principle is the core of object-oriented design, and following this principle can bring the huge benefits claimed by object-oriented technology, namely maintainability, extensibility, reusability, and flexibility. Developers should abstract only those parts of the program that present frequent changes, however deliberately abstracting every part of the application is also not a good idea, rejecting premature abstractions is as important as the abstraction itself. The open-closed principle, which guarantees the correctness of the previous code, ensures that the developer can focus on putting the design on the newly extended code because the previous code is not modified.
Simply use a classic sentence: the past has become history and cannot be modified, because time cannot be reversed, but what you plan to do now or tomorrow can be determined (ie expanded) by yourself.

2. Liskov Substitution Principle
Definition 1: If for every object o1 of type T1, there is an object o2 of type T2, so that all programs P defined by T1 are substituted for all objects o1 When changing to o2, the behavior of program P does not change, then type T2 is a subtype of type T1.
Definition 2: Subtypes must be able to replace their supertypes.
    Description: If a software entity uses a parent class, it must be applicable to its subclass, and it cannot detect the difference between the parent class object and the subclass object, that is, in the software, replace the parent class into its subclass, the behavior of the program does not change
Example: In biological classification, penguin is a kind of bird, but in programming world, penguin cannot inherit bird. In object-oriented design, the subclass has all the non-private behaviors and properties of the parent class. Birds can fly, but penguins can't, so penguins cannot inherit birds.
    Only when the subclass can replace the parent class and the function of the software unit is not affected, the parent class can be truly reused, and the subclass can also add new behaviors on the basis of the parent class. The principle makes inheritance and reuse possible.
It is precisely because of the substitutability of subtypes that modules using the supertype type can be extended without modification. Otherwise, what is the extension opening and modification closed? Extend the function of the parent class, but cannot change the original function of the parent class. It contains the following four meanings:
1. A subclass can implement the abstract methods of the parent class, but cannot override the non-abstract methods of the parent class.
2. Subclasses can add their own unique methods.
3. When the method of the subclass overloads the method of the parent class, the preconditions of the method (that is, the formal parameters of the method) are more relaxed than the input parameters of the parent class method.
4. When the method of the subclass implements the abstract method of the superclass, the post-condition of the method (ie the return value of the method) is stricter than that of the superclass.
    It seems incredible, because we will find that we often violate the Liskov Substitution Principle in our own programming, and the program still runs fine. So everyone will have this question, what will be the consequences if I have to follow the Liskov substitution principle?
The consequence is that the chances of the code you write going wrong are greatly increased.

3. Dependence Inversion Principle (Dependence Inversion Principle)
definition: high-level modules should not depend on low-level modules, both should depend on their abstractions; abstractions should not depend on details; details should depend on abstractions. That is, programming for the interface, not for the realization of the programming
    dependency inversion, in fact, do not depend on anyone, except for the agreed interface, everyone can be flexible. Dependency inversion can be said to be a sign of object-oriented design. It doesn’t matter which language you use to write the program. If you think about how to program for abstraction rather than for details, all dependencies in the program end in abstraction. Class or interface, that is object-oriented design, otherwise it is procedural design. If the various components or classes of the design depend on each other, the coupling degree is high, and it is difficult to maintain and extend, which does not reflect the benefits of object-oriented.
    The principle of dependency inversion is like a team, there is a demand group, a development group, a test group, the development group and the test group are all faced with the same requirements, and then do their own corresponding work, not the test group according to the needs understood by the development group To do test cases, that is to say, both the development team and the test team work directly with the requirements team. Everyone's purpose is the same, to ensure that the product is launched on time, and the requirements are not dependent on development and testing.
    The Dependency Inversion Principle is based on the fact that abstract things are much more stable than details are variable. Architectures built on abstraction are much more stable than architectures built on details. In java, abstract refers to an interface or abstract class, and details are specific implementation classes. The purpose of using interfaces or abstract classes is to formulate specifications and contracts, without involving any specific operations, and leave the task of showing details to their implementation class to complete.
    The central idea of ​​the Dependency Inversion Principle is interface-oriented programming. There are three ways to transfer dependencies. The above is about interface transfer. There are also two transfer methods: constructor transfer and setter method transfer. I believe that those who have used the Spring framework, You must be familiar with how dependencies are passed.
In actual programming, we generally need to do the following three points:
low-level modules should have abstract classes or interfaces as much as possible, or both.
Variables should be declared as abstract classes or interfaces as much as possible.
Follow the Liskov substitution principle when using inheritance.
    In a word, the principle of Dependency Inversion is to ask us to program interface-oriented, understand interface-oriented programming, and also understand Dependency Inversion.

4. Interface Segregation Principle (Interface Segregation Principle)
   The meaning of the interface segregation principle is: build a single interface, do not build a huge and bloated interface, try to refine the interface, and minimize the methods in the interface. That is to say, we have to create dedicated interfaces for each class, instead of trying to create a huge interface for all classes that depend on it to call. In programming, it is more flexible to rely on several specialized interfaces than to rely on one comprehensive interface. An interface is a "contract" set to the outside during design. By defining multiple interfaces in a decentralized manner, the proliferation of external changes can be prevented, and the flexibility and maintainability of the system can be improved.
   At this point, many people think that the interface isolation principle is very similar to the single responsibility principle, but it is not. First, the single responsibility principle originally focused on responsibility; the interface isolation principle focused on the isolation of interface dependencies. Second, the principle of single responsibility is mainly to constrain classes, followed by interfaces and methods, which are aimed at the implementation and details in the program; while the principle of interface isolation mainly constrains the interface interface, mainly for abstraction, for the construction of the overall framework of the program.
When using the interface isolation principle to constrain the interface, pay attention to the following points:
1. The interface should be as small as possible, but limited. It is a fact that refining the interface can improve the flexibility of programming, but if it is too small, it will cause too many interfaces and complicate the design. So be in moderation.
2. Customize the service for the class that depends on the interface, only expose the methods it needs to the calling class, and hide the methods it does not need. Minimal dependencies can only be established by focusing on providing custom services for one module.
3. Improve cohesion and reduce external interaction. Make the interface do the most things with the fewest methods.
   The principle of interface isolation must be used in moderation. It is not good to design an interface that is too large or too small. When designing an interface, you can only practice this principle accurately if you spend more time thinking and planning.

5. Law of Demeter
    The fundamental idea of ​​the Law of Demeter is to emphasize the loose coupling between classes. The weaker the coupling between classes, the more conducive to reuse. A class in weak coupling Being modified, it will not affect the related classes, that is to say, the hiding of information promotes the reuse of software.
    Since we started programming, we have known the general principles of software programming: low coupling, high cohesion. Whether it is procedural programming or object-oriented programming, the code reuse rate can be improved only if the coupling between each module is as low as possible. The advantages of low coupling are self-evident, but how to program to achieve low coupling? That's exactly what the Law of Demeter is trying to accomplish.
    The Law of Demeter, also known as the principle of least known, was first proposed by Ian Holland of Northeastern University in the United States in 1987. In layman's terms, the less a class knows about the classes it depends on, the better. That is to say, for the dependent class, no matter how complicated the logic is, try to encapsulate the logic inside the class as much as possible, and do not leak any information to the outside except for the public methods provided. The Law of Demeter has an even simpler definition: Only communicate with immediate friends. First, let's explain what a direct friend is: each object will have a coupling relationship with other objects. As long as there is a coupling relationship between two objects, we say that the two objects are friends. There are many ways of coupling, such as dependency, association, composition, aggregation, etc. Among them, we call the classes that appear in member variables, method parameters, and method return values ​​as direct friends, while classes appearing in local variables are not direct friends. That is to say, unfamiliar classes are best not to appear inside the class in the form of local variables.
To sum it up in one sentence: an object should keep the least amount of knowledge about other objects.

6. Single Responsibility Principle (Single Responsibility Principle)
Definition: There should not be more than one reason for a class change. In layman's terms, a class is only responsible for one responsibility, and there should be only one reason for its change.
    When it comes to the single responsibility principle, many people will dismiss it. Because it's too simple. Even experienced programmers who have never read Design Patterns and have never heard of the Single Responsibility Principle will consciously follow this important principle when designing software because it is common sense. In software programming, no one wants to modify one function to cause other functions to fail. The way to avoid this problem is to follow the Single Responsibility Principle. Although the Single Responsibility Principle is so simple and considered common sense, even the programs written by experienced programmers will have code that violates this principle. Why would such phenomenon happen? Because of the spread of responsibility. The so-called responsibility diffusion is that for some reason, the responsibility P is divided into finer-grained responsibilities P1 and P2.
The advantages of following the single responsibility principle are:
1. It can reduce the complexity of the class. A class is only responsible for one responsibility, and its logic must be much simpler than responsible for multiple responsibilities;
2. Improve the readability of the class and improve the system Maintainability;
3. The risk caused by changes is reduced, and changes are inevitable. If the single responsibility principle is followed well, when one function is modified, the impact on other functions can be significantly reduced.
It should be pointed out that the single responsibility principle is not only unique to the idea of ​​object-oriented programming, as long as it is a modular program design, it needs to follow this important principle.

 

7. The principle of composition/aggregation reuse
means to use synthesis and aggregation as much as possible instead of inheritance to achieve the purpose of reuse.
The principle is to use some existing objects in a new object to make them part of the new object : New objects reuse existing functions by delegating to these objects.
      In fact, the final point here is to distinguish the difference between "has-a" and "is-a". Compared with synthesis and aggregation,
the disadvantage of inheritance is that the methods of the parent class are all exposed to the child class. If the parent class changes, the child class must also change. When the aggregation is reused, there is less dependency on other classes. .
Synthesis/aggregation reuse
① Advantage:
The only way for a new object to access a component object is through the interface of the component object;  this
 reuse is black-box reuse because the internal details of the component object are invisible to the new object;
Wrapped with support;
this reuse requires fewer dependencies;
each new class can focus on a single task;
 this reuse can be done dynamically at runtime, new objects can use composition/aggregation relationships The responsibility is delegated to the appropriate object.
② Disadvantage:
The system built by reuse in this way will have more objects to manage.
Inheritance and reuse
① Advantages:
  The new implementation is easier, because most of the functions of the base class can automatically enter the derived class through the inheritance relationship;
  it is easier to modify or extend the inherited implementation.
② Disadvantages:
  Inheritance reuse destroys packaging, because inheritance exposes the implementation details of the base class to the derived class. This reuse is also called white-box reuse; if the implementation of the base class changes, the implementation of the derived class has to change too; The implementation inherited from the base class is static, cannot be changed at runtime, and is not flexible enough.

Guess you like

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