Foreword: read “design mode of zen” have a feeling, here extract some design principles plus their own understanding, strive for easy to understand, hope can expound the author’s thoughts, thank the author!

— Although the book is the Java language to do the example (illustration), but the principle is the same, iOS children shoes also do not worry about the basic can understand, some and OC big difference between the noun I have also made annotations, does not affect the understanding of the principle!

Six design Principles, 23 design patterns, VS between patterns, extensions… It is suggested to start with the design principle first. The design principle can be seen as an internal mental method, while the design mode as a martial arts move, which needs both internal and external repair. I have a good understanding of the principles, and when I look at the 23 models, I will find that these six principles are everywhere! Here are six principles:

Table of Contents (Six Principles)

  • Single responsibility (only one reason for a class to change)
  • Richter substitution
  • Dependency inversion (concrete class, abstract class)
  • Interface isolation (Interface refinement)
  • Demeter’s Rule (The less you know, the better)
  • Open closed principle (open for extensions, closed for modifications)

1. Principle of single responsibility

The English name for the Single Responsibility Principle is the SRP definition: there is only one reason for a class to change

The principle is controversial, mainly over the definition of “duty”

1.1 What are Responsibilities?

Responsibilities are not measurable and vary according to requirements.

For example, a user object, which contains information and behavior about the user, has the following user class interface:

What’s wrong with this code? Satisfies all the methods of an object, but by another definition,UserInfoThe userInfo class contains the user’s properties and behavior, and any change to either will cause a change to the current userInfo class, which is not strictly consistent with the single responsibility rule

IUserBo is responsible for properties: only user properties change the current class. IUserBiz is responsible for behavior: Only user behavior changes the current class.

In line with what we call the single responsibility principle, we say that different responsibility definitions lead to different parts of our business

1.2 How to distinguish responsibilities?

Extending the definition here: The single responsibility principle requires that an interface or class has only one reason to change, that is, if an interface or class has only one responsibility, it is responsible for one thing

For example: Modify oneIUserManagerClass interface: This interface changes User for a number of reasons, such as: userName, HomeAddress, officeTel… Etc.What if I change it like this

Each interface has clear responsibilities and structure

What are the benefits of the single responsibility principle:

Class complexity is reduced, and what responsibilities are implemented are clearly defined; Readability goes up, complexity goes down, so readability goes up; Increased maintainability, increased readability, which of course is easier to maintain; To reduce the risk caused by change, change is essential. If the single responsibility of the interface is well done, an interface modification only affects the corresponding implementation class, and has no impact on other interfaces, which is of great help to the expansibility and maintenance of the system.

1.3 Use it flexibly, not dogmatism

If we look at many open source frameworks, we rarely meet a single principle in terms of classes. For example, if we split two classes in userInfo, we will have to maintain two identical life cycles. So for the single responsibility principle, my suggestion is that interfaces should be single responsibility, and classes should be designed for only one reason.

Note: The single responsibility principle provides a standard for writing programs that measure how well an interface or class is designed by responsibility or reason for change, but responsibility and reason for change are not measurable, vary from project to project, and from environment to environment.

2. Richter’s Rule

Definition: All references to a base class must transparently use the objects of its subclasses

2.1 Familiar Scenarios

Object-oriented languages, which we’ve used before, have the following advantages:

  • Code sharing reduces the amount of class creation, with each subclass owning the methods and attributes of its parent class.
  • Improve code reuse;
  • “Dragon born dragon, chicken born chicken, mice born to make holes” means that a son has the “seed” of his father. “There are no two identical leaves in the world” indicates the difference between a son and his father.
  • By increasing the extensibility of code, methods that implement the parent class can “do whatever they want”. Many open source frameworks extend interfaces by inheriting the parent class.
  • Improve the openness of the product or project.

All things in nature are advantages and disadvantages coexist, even eggs, sometimes also can pick out the bone, inherited disadvantages are as follows:

  • Inheritance is intrusive. As long as you inherit, you must have all the attributes and methods of the parent class;
  • Reduce code flexibility. Subclasses must have the attributes and methods of their parent class, making the subclass a little more constrained in its free world.
  • Enhanced coupling. When constants, variables, and methods of the parent class are changed, subclass changes need to be considered, and in the absence of specifications, such changes can have very bad results — large chunks of code need to be refactored.

2.2 Interpretation of Definitions

The Richter substitution principle customizes a specification for good inheritance, not to underestimate the fact that a simple definition contains four layers of meaning:

  • 2.2.1 Subclasses must fully implement the methods of their parent class

For example: played CS game, gun class diagramAbstract base class AbstractGun as guns, shoot shoot () function If add a toy gun (don’t shoot function), want to also inherit the abstract base class, inheritance as if no problem, also can not call or overwrite the shoot (), so that they don’t have shooting function, but it is not recommended to do so, a more reasonable way class diagram: Notice If the subclass cannot completely implement the methods of the parent class, or some methods of the parent class have “distortion” in the subclass, it is recommended to disconnect the parent-child inheritance relationship and use dependency, aggregation, and composition relationships instead of inheritance.

  • 2.2.2 Subclasses may have their own personalities

Subclasses can have their own methods and attributes, and the corresponding subclass can be competent for the parent class, but the parent class cannot be competent for the child class

  • 2.2.3 Input parameters are amplified when overwriting or implementing methods of the parent class

The parent class

Public class Father {receive_message public Collection doSomething(receive_message){receive_message public Collection doSomething(receive_message) );  return map. The values ();  }}Copy the code

A subclass

Public class Son extends Father {receivea public Collection doSomething(receivea){receivea. );  return map. The values ();  }}Copy the code

Subclass the same as the superclass method name, parameter range is different, this is not overwrite the overloading, subclass parameters input is greater than the parent class, subclass call doSomething will perform the superclass method, if we want to perform a subclass methods must be rewritten, in line with the way we want, but if the parent class input parameter range is greater than the subclass, please remember a word: Where there is a parent class, the child class should be fully competent. We call the method of the child class, without the parent class method, without overwriting, and achieve the child class without the parent class, which is inconsistent with our common logic. It is possible that in the actual scene, we call the method to use the parent class method, but the effect is to use the child class method

2.2.4 When overwriting or implementing a method of a parent class, the return result can be reduced

When a parent class returns a type T, the subclass’s same method (overridden or overridden) returns S. Richter’s substitution rule requires that S must be less than or equal to T. That is, either S and T are the same type, or S is a subset of T

3. Dependency inversion

The original definition was: High level modules should not depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstractions. A high-level module should not depend on a low-level module; both should depend on its abstraction. Abstraction should not depend on details; Details should depend on abstractions. A simple example: a driver in a MercedesDriverAs a driverBenzAs a carWhat if the driver is buying a BMW? Will we recreate the BMW class and add it in turn? They have abstract commonalities, both cars, both canrun()At this time, we should establish the abstract class ICar. The performance of Mercedes-benz and BMW is different, and then the specific class is refined.

Conclusion: The essence of dependency inversion principle is to make the implementation of each class or module independent from each other and not affect each other through abstraction (interface (similar protocol in OC) or abstract class), so as to achieve loose coupling between modules. The following rules can be followed:

  • As much as possible, every class has an interface, an abstract class, or both
  • The ostensible type of a variable should be an interface or abstract class
  • No class should be derived from a concrete class
  • Try not to overwrite base class methods
  • Used in conjunction with the Richter substitution principle

4. Isolate interfaces

Definition: a client should not rely on interfaces it does not need. If this is a bit confusing, let’s look at the second definition: dependencies between classes should be established on the smallest interface

  • What is an interface?

Here interface can be understood as an instance of the object of the instance interface and class interface, Java development is not a bit confused, from another point of view, Java class is also a kind of interface, this is the author said not I said, pay attention to the brick orientation, as OC development is easier to accept this concept

  • So how do we get to the minimum interface?
  1. Interface as small as possible

Is the same as the single responsibility mentioned above, as far as possible the single responsibility

  1. High cohesive interface,

For example, if your leader asks you to do something, it may be divided into A, B and C, and you only need to report to the leader that the task has been completed. The leader does not need to know the details of the process. In terms of a single responsibility, A, B and C should be divided into separate events, but the external interface only needs to be provided to complete the task. High cohesion, as little exposure as possible; For attribute external read-only, never give read and write permission, public method is also, reduce external influence, interface is external commitment, commitment less is more beneficial to system development

  1. Module custom

For example, in a library query system, we provide classes that can be categorized by author, title, publisher, etc., and mixed queries

This method is not clearly used by other service providers, and the mixed query method is applied to each query, resulting in unusually slow system speed. Therefore, the system is isolated and customized interfaces are provided for service providersThe smaller the granularity of interface design, the more flexible the system, this is an indisputable fact, but flexibility also brings complexity of structure, development difficulty, reduced maintainability, so the interface design must pay attention to moderate, how to judge this “degree”? As a rule of thumb and common sense, there is no fixed or measurable standard.

Demeter’s Rule

Definition: Also for the least known principle, one object should know the least about other objects,

It doesn’t matter to me how complex the inner part of the class being called is. I know that you provide so many Public methods that I care about calling so many, and nothing else. There are three main meanings:

  • Just friends

At least friends think, do not need to know friends of friends, as long as you know this friend, your friend will find his friends to help you do good things. Only to oneself must contact the object to carry on the association, the unnecessary object reduces the coupling, should not establish the relationship with too many objects, if too much should consider how to divide the management, “as far as possible to achieve all over the body bones, rather than fat toot!”

  • Friends should be kept at arm’s length

Even between related classes, corresponding “distance” should be maintained, not omniscient, do not need to fully expose all details, this is the aforementioned high cohesion, only provide public methods, specific implementation does not need to be exposed, note: Demeter’s rule requires classes to be “shy”, not to expose too many public methods and non-static public variables, to be more introverted, and to use more private access.

  • Own or own

In practice, there is often a method: it is ok to put in this class, and it is not wrong to put in other classes, so how to measure? You can stick to the principle that if a method is placed in a class that neither adds to the relationship between classes nor negatively affects the class, it should be placed in the class.

Conclusion: The core concept of Demeter’s law is decoupling and weak coupling between classes. Only after the weak coupling, the reuse rate of classes can be improved. The result of this requirement is a large number of relay or jump classes, which increases the complexity of the system as well as the difficulty of maintenance.

6. Open and Close Principle (top priority)

The core point finally comes, is the open and closed principle, philosophically says that the law of contradiction is the most fundamental law of materialist dialectics, that open and closed principle, can be used as the most basic design principle. Definition: Software entities like classes,modules and functions should be open for extension but closed for Modifications. (A software entity such as classes, modules, or functions that should be open to extension and closed to modification.) My favorite: Close to Change, Open to Extension The open to close principle tells us that we should try to achieve change by extending the behavior of software entities, not by modifying existing code. It is a principle that constrains current development design for future events of software entities.

Take, for example, a bookstore that sells fiction books:IBookAs an abstract class, it defines three attributes of the data: name, price, and authorNovelBookFor a concrete subclass, get novel book information

If the bookstore at this time to discount processing, how can we modify the above class, we will be earlier than the NovelBook classgetPrice()To add discount information, actually not recommended, think of the sentence:Closed for modifications, open for extensionsIn accordance with the open and closed principle, we on the originalNovelBookThe class should not be modified, but extended with a discountOffnoveBookSubclasses have the following structure:If the sales of other books are added later, such as computer books, we just need to expand the new subclass on the original basis, with the structure as follows:Conclusion: The open and closed principle is a very abstract concept, but also a very empty concept, it is simple definition, but not simple, we are always embracing change, think how to keep it follow the open and closed principle.

What should I pay attention to when using the open/closed principle

  • Open and close is just a principle. There are many ways to embrace change, but the prerequisite is that classes must be highly cohesive and low-coupling, so that they can embrace change with fewer unexpected failures
  • Project rules and regulations are very important. Having a stable rule and an agreement that all members must abide by can bring us many benefits, such as improving development efficiency, reducing defect rate and reducing maintenance costs
  • Anticipate change

In the field, when an architect or project manager discovers the possibility of change, he or she needs to consider how easily the existing architecture can accommodate the change. An architect designs a system that not only meets existing requirements, but also ADAPTS to possible changes.

The open closed principle is an ultimate goal that no one, including a master, can achieve 100%, but working in this direction can dramatically improve the architecture of a system and truly “embrace change.”

Conclusion:

The pain of software design is embracing change, which is unpredictable and requires us to prepare for unpredictable requirements. The six design principles and 23 design patterns summarized by predecessors are to help us “embrace” future changes, but they are not dogmatic and become the border that limits us; Flexible use, because of the place and different, there may be a few big principles between the scene conflict, we should understand their own use!

Denver annual essay | 2020 technical way with me The campaign is under way…