Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the principles of software design?

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the relevant knowledge of "what are the principles of software design". In the operation of actual cases, many people will encounter such a dilemma. Next, let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Don't Repeat Yourself (DRY)

DRY is the simplest rule and the easiest to understand. But it is also probably the hardest to apply (because to do so, we need to make a lot of effort on generic design, which is not an easy task). It means that when we find some similar code in two or more places, we need to abstract their commonalities into a unique new method. and change the existing code so that they call the new method with some appropriate parameters.

Keep It Simple, Stupid (KISS)

KISS principles may be the most respected in design, in home decoration design, interface design, operation design, complex things are more and more BS, while simple things are more and more recognized, such as these UI designs and our Chinese web pages (especially Sina's web pages) are negative examples. " IKEA's simple and efficient home design and production ideas; Microsoft's WYSIWYG concept; and Google's simple and direct business style, without exception, follow the "kiss" principle, and it is the "kiss" principle that makes these seemingly magical business classics. Apple's iPhone/iPad takes this principle to the extreme.

It is a simple thing to make a thing complicated, but it is a complicated thing to make a complex thing simple.

Program to an interface, not an implementation

This is the most fundamental philosophy in the design pattern, focusing on interfaces rather than implementation, relying on interfaces rather than implementation. Interfaces are abstract and stable, and implementations are diverse. Our dependency inversion principle will be mentioned later in the object-oriented SOLID principle, which is another way of looking at this principle. There is also a principle called Composition over inheritance (like to combine rather than inherit), these two are the design principles of the 23 classic design patterns.

Command-Query Separation (CQS)-Command-query Separation principle

Query: when a method returns a value in response to a question, it has the nature of a query

Command: when a method wants to change the state of an object, it has the nature of a command.

In general, a method may be pure Command mode or pure Query mode, or a mixture of both. When designing an interface, if possible, the interface should be simplified as much as possible to ensure that the behavior of the method is strict with commands or queries, so that the query method does not change the state of the object and has no side effects. methods that change the state of an object cannot have a return value. In other words: if we are going to ask a question, it should not affect its answer. In practical application, it depends on the specific situation, and there is a tradeoff between semantic clarity and simplicity of use. Combining Command and Query functions into one method makes it easy for customers to use, but reduces clarity, and may not be convenient for assertion-based programming and requires a variable to hold the query results.

In the system design, many systems are also designed according to this principle, the query function is separated from the command function, which is not only good for the system performance, but also conducive to the security of the system.

You Ain't Gonna Need It (YAGNI)

This principle is simply described as-- only consider and design the necessary functions to avoid overdesign. Only implement the functionality you need now, and you can add it later when you need more functionality.

Do not add complexity if it is not necessary.

Software development is first a communication game.

In the past, there was an article on excessive refactoring on this site, and this example is a counterexample of this principle. The designer of WebSphere, on the other hand, said he overdesigned the product. When designing a system, our programmers or architects will consider a lot of extensibility, resulting in a lot of tradeoffs between architecture and design, leading to project failure. This is an ironic lesson because the life cycle of the project was shortened when it was intended to extend the project life cycle as much as possible.

Law of Demeter-Dimitt rule

Dimitt's Law (Law of Demeter), also known as the principle of least knowledge (Principle of Least Knowledge), originated from a project called Demeter at the University of the Netherlands in 1987. Craig Larman also calls Law of Demeter "Don't talk to strangers". The chapter on LoD in "the way programmers practice" is called "decoupling and Demeter's Law". There are some vivid metaphors about Dimitt's rule:

If you wanted your dog to run, would you say it to the dog or to the four dog legs?

If you go shopping in the store, will you give the money to the clerk, or will you give the clerk his wallet and let him take it himself?

Talking to the dog's limbs? Let the clerk take the money out of his wallet? It sounds ridiculous, but it's almost common in our code.

For LoD, the formal statement is as follows:

For one of the methods in the object'O', the methods in the following objects should only be accessible to the methods in the following objects:

Object O

Component Object directly related to O

Objects created or instantiated by method M

An object that is an argument to method M.

In the book "Clean Code", there is a passage in Apache framework that violates LoD's code:

Final String outputDir = ctxt.getOptions (). GetScratchDir (). GetAbsolutePath ()

Such a long list of details of other objects, as well as details of details, details of details. Call, increase the coupling, make the code structure complex, rigid, difficult to expand and maintain.

There is a "Feature Envy" in the loop flavor of the code in ReFactor, which vividly describes a violation of LoC. Feature Envy means that an object is more interested in the content of other objects, that is, it always envies the members, structures, or functions of other objects, and invokes other people's things all the way. Such a structure is obviously unreasonable. Our program should be written "shyly". You can't take out the money by taking out the guest's wallet like the clerk in the previous example who doesn't think of himself as an outsider. The "shy" program only talks to your closest friends. In this case, you should adjust the structure of the program so that the object has the feature it envies, or use reasonable design patterns (such as Facade and Mediator).

Object-oriented S.O.L.I.D principle

Generally speaking, these are the five major principles of object-oriented design, but I think these principles can be applied to all software development.

Single Responsibility Principle (SRP)-principle of single responsibility

With regard to the principle of single responsibility, its core idea is: one class, do only one thing, and do it well, there is only one reason for its change. The principle of single responsibility can be regarded as an extension of the object-oriented principle of low coupling and high cohesion. Responsibility is defined as the cause of change in order to improve cohesion to reduce the cause of change. If there are too many responsibilities, the more reasons that may cause it to change, which will lead to responsibility dependence and influence each other, thus greatly damaging its cohesion and coupling. A single responsibility usually means a single function, so don't implement too many function points for a module to ensure that the entity has only one reason for its change.

Unix/Linux is the embodiment of this principle. Each program is independently responsible for a single thing.

Windows is a negative example of this principle. Almost all programs are intertwined and coupled.

Open/Closed Principle (OCP)-opening and closing principle

With regard to the closed principle of development, the core idea is that the module is extensible and unmodifiable. That is, it is open to extensions and closed to modifications.

Being open to extension means that when there are new requirements or changes, existing code can be extended to adapt to the new situation.

Closing the modification means that once the class is designed, it can do its work independently without making any changes to the class.

For object-oriented, you need to rely on abstraction rather than implementation, which is the "strategy pattern" of the 23 classic design patterns. For non-object-oriented programming, some API require you to pass in a function that you can extend, such as our C language qsort () allows you to provide a "comparator", the memory allocation of container classes in STL, and multithreaded locks in ACE. On the software side, various plug-ins for browsers belong to the practice of this principle.

Liskov substitution principle (LSP)-Richter substitution principle

Robert C. Martin, a master of software engineering, finally simplified the Richter substitution principle to one sentence: "Subtypes must be substitutable for their base types". That is, subclasses must be able to be replaced with their base classes. That is, the subclass should be able to replace any place where the base class can appear, and after replacement, the code will work properly. In addition, conditions such as if/else to determine the subclass type should not appear in the code. The Richter substitution principle LSP is an important guarantee to make the code conform to the open-closed principle. It is because of the replaceability of the subtype that the module of the parent type can be extended without modification.

In this way, it seems a bit dogmatic, and I very much suggest that you take a look at the two most classic cases of this principle-"a square is not a rectangle" and "an ostrich is not a bird". Through these two cases, you will understand what Mozi Xiaoquan said-"Di, beauty is also, love Di, not beauty is also …... thieves are also people; evil thieves are not evil people." Although my sister is a beauty, just because she likes her doesn't mean she likes beauties. Thieves are human beings, but just because they hate thieves doesn't mean they hate human beings. This principle allows you to consider not the relationship between semantic objects, but the environment of the actual requirements.

In many cases, the relationship between our classes is not very clear at the beginning of the design, and LSP gives us a benchmark for judging and designing the relationship between classes: whether inheritance is needed and how to design the inheritance relationship.

Interface Segregation Principle (ISP)-Interface isolation principle

The principle of interface isolation means that the function is implemented in an interface rather than in a class, and it is better to use multiple specialized interfaces than a single master interface.

For example, we have different ways to use computers, such as writing, communication, watching movies, playing games, surfing the Internet, programming, computing, data, etc., if we declare these functions in the extraction of computers, then, our netbooks, PCs, servers and notebooks all have to implement all these interfaces, which is too complicated. Therefore, we can isolate these functional interfaces, such as work-study interface, programming development interface, Internet entertainment interface, computing and data service interface, so that our computers with different functions can selectively inherit these interfaces.

This principle can improve our "building block" software development. For design, all kinds of Event Listener and Adapter in Java, for software development, different user rights have different functions, and different versions have different functions, which are all applications of this principle.

Dependency Inversion Principle (DIP)-dependency inversion principle

High-level modules should not rely on the implementation of low-level modules, but on high-level abstractions.

For example, the switch on the wall should not depend on the implementation of the light switch, but on the standard interface of an abstract switch, so that when we extend the program, our switch can also control other different lights. even different appliances. In other words, lights and other appliances inherit and implement our standard switch interface, and our switch manufacturers do not need to care about what kind of equipment they want to control, just care about that standard switch standard. This is the principle of relying on inversion.

It's as if the browser doesn't rely on the subsequent web server, it only depends on the HTTP protocol. This principle is really too important, social division of labor, standardization are the embodiment of this design principle.

Common Closure Principle (CCP)-the principle of common closure

All classes in a package should be turned off for the same type of change. If a change affects a package, it affects all the classes in the package. A shorter statement is that classes modified together should be grouped together (in the same package). If you have to modify the code in the application, we want all the changes to take place in one package (modification turned off), rather than spread across many packages. The CCP principle is to combine all classes that need to be modified for the same reason into one package. If the two classes are physically or conceptually closely related and they usually change together, then they should belong to the same package.

CCP extends the "close" concept of the open-close principle (OCP), limiting the scope of modification to a minimum package when it needs to be modified for some reason.

Common Reuse Principle (CRP)-the principle of common reuse

All classes of the package are reused together. If you reuse one of these classes, reuse all of them. In other words, classes that are not reused together should not be grouped together. The CRP principle helps us decide which classes should be put in the same package. To rely on a package is to rely on everything that the package contains. When a package changes and a new version is released, all users who use the package must verify their work in the new package environment, even if the parts they use remain unchanged. Because if the package contains an unused class, even if the user does not care whether the class has changed, the user still has to upgrade the package and retest the original functionality.

CCP benefits maintainers of the system. CCP makes the package as large as possible (the CCP principle adds functional classes), and CRP makes the package as small as possible (the CRP principle removes unused classes). Their starting points are different, but they do not conflict with each other.

Hollywood Principle-Hollywood principle

The Hollywood principle is a sentence-"don't call us, we'll call you." It means that Hollywood agents don't want you to contact them, but they will contact you when they need it. In other words, all components are passive, and all component initialization and invocation are the responsibility of the container. The component is in a container and is managed by the container.

To put it simply, the relationship between programs is controlled by the container, rather than directly controlled by the program code in the traditional implementation. This is the concept of the so-called "inversion of control":

Instead of creating an object, describe how it is created.

In the code, the object is not directly related to the service, but the container is responsible for linking them together.

The control is transferred from the application code to the external container, and the transfer of control is called reversal.

The Hollywood principle is the basic principle of IoC (Inversion of Control) or DI (Dependency Injection). This principle is much like relying on the inversion principle, relying on interfaces rather than instances, but what this principle is trying to solve is how to get this instance into the calling class? You may declare it as a member, you can use the constructor, you can use the function argument. But IoC allows you to generate the actual configuration class through the configuration file, a configuration file read by Service Container. But the program may also become difficult to read, and the performance of the program may decline.

High Cohesion & Low/Loose coupling &-High cohesion, low coupling

This principle is a classic principle of UNIX operating system design, which reduces the coupling between modules to *, and strives to make a module strive for excellence.

Cohesion: the degree to which elements within a module are bound to each other

Coupling: a measure of the degree of interconnection between different modules within a software architecture

Cohesion means reuse and independence, and coupling means that the domino effect leads the whole body.

Convention over Configuration (CoC)-conventions take precedence over configuration principles

To put it simply, use some accepted configuration methods and information as internal default rules. For example, Hibernate's mapping file, if the convention field name and class properties are the same, basically do not need this configuration file. Your application only needs to specify information that is not convention, thus reducing a lot of convention and having to spend time and effort on long-winded things. Configuration files often have a considerable impact on development efficiency.

There are few configuration files in Rails (but not none, a database connection is a configuration file), and Rails's fans is 10 times more efficient than java development, which is probably why. Maven also uses the CoC principle, when you execute the mvn-compile command, you do not need to point to where to put the source file, and the compiled class file is not specified anywhere, this is the CoC principle.

Separation of Concerns (SoC)-Separation of concerns

SoC is one of the most important goals in computer science. This principle is to separate the concerns of the problem by various means in software development. If a problem can be decomposed into independent and smaller problems, it is relatively easy to solve. The problem is too complex, there are too many points to focus on to solve the problem, and the programmer's ability is limited to focus on all aspects of the problem at the same time. Just as programmers' memory is so limited relative to computer knowledge, programmers' ability to solve problems is also very limited relative to the complexity of the problems to be solved. When we analyze the problem, if we mix everything up and discuss it, there will be only one result-chaos.

I remember there was a project in the last company, which was discussed for more than a year. The project was not complicated, but it didn't use SoC, and everything got mixed up, plus a bunch of programmers injected different ideas and ideas, and the whole project got out of control. *, originally a 1-year project has been done for 3 years.

There are two main ways to realize the separation of concerns, one is standardization, the other is abstraction and packaging. Standardization is to develop a set of standards, let users abide by it, and unify people's behavior, so that people who use standards do not have to worry that others will have many different implementations, so that their own programs can not cooperate with others. Java EE is a large collection of standards. Every developer only needs to focus on the standard itself and what he is doing. It's like people who develop screws only focus on developing screws, without paying attention to how the caps are made. Anyway, the caps and screws will fit according to the standard. Constantly packaging the aberration of some parts of the program is also a good way to achieve separation of concerns. Once a function is abstracted and implemented, the user of the function does not have to care about how the function is implemented, similarly, once a class is abstracted and implemented, the users of the class no longer have to worry about how the class is implemented internally. Concepts such as components, layering, service orientation, etc., are abstracted and packaged at different levels so that users do not have to care about the details of its internal implementation.

To put it bluntly, it is still "high cohesion, low coupling".

Design by Contract (DbC)-Design by contract

The core idea of DbC is the cooperation between the elements in the software system and the metaphor of "responsibility" and "obligation". This analogy comes from the "contract" between "customer" and "supplier" in business activities. For example:

The supplier must provide a certain product (responsibility) and he has the right to expect the customer to have paid (right).

The customer must pay (responsibility) and have the right to the product (right).

The parties to the contract must perform those obligations that are valid for all contracts, such as laws and regulations.

Similarly, if a module provides a function in programming, it should:

All client modules that call it are expected to guarantee certain entry conditions: these are the prior conditions of the module (the obligations of the customer and the rights of the supplier, so that it does not have to deal with cases where the prior conditions are not met).

A specific attribute is given when the exit is guaranteed: this is the posterior condition of the module (the obligation of the supplier and obviously the right of the customer).

Assume on entry and maintain some specific properties on exit: invariants.

The contract is the formal form of these rights and obligations. We can summarize DbC with "three questions", and as designers, we should often ask:

What does it expect?

What does it guarantee?

What does it want to keep?

According to the description of the concept of DBC put forward by Bertrand Meyer, for a method of a class, there is a prerequisite and a subsequent condition, which indicates what kind of parameter data the method accepts, and so on. Only when the prerequisite is satisfied can this method be called. At the same time, the subsequent condition is used to describe the state of the method when it is completed, and if the execution of a method will cause the subsequent condition of the method to be invalid, then the method should not return normally.

Now that the prerequisites and subsequent conditions are applied to the inherited subclass, the subclass method should satisfy:

The prerequisite is not stronger than the base class.

The subsequent condition is not weaker than the base class.

In other words, when an object is called through the interface of the base class, the user knows only the base class prerequisites and subsequent conditions. Therefore, the inherited class must not require the user to provide stronger prerequisites than the base class method requires, that is, the inherited class method must accept any conditions (parameters) that are acceptable to any base class method. Similarly, the inherited class must comply with all subsequent conditions of the base class, that is, the behavior and output of the inherited class methods must not violate any constraints established by the base class and do not confuse the user with the output of the inherited class methods.

In this way, we have a contract-based LSP, and contract-based LSP is a reinforcement of LSP.

Acyclic Dependencies Principle (ADP)-acyclic dependency principle

The dependency structure between packages must be a direct acyclic graph, that is, rings (circular dependencies) are not allowed in the dependency structure. If the package dependency forms a ring structure, how do you break this circular dependency? There are two ways to break this circular dependency: * the way is to create a new package, and if A, B, and C form a loop dependency, extract these common classes and put them in a new package D. In this way, C dependence A becomes C dependence D and A dependence D, thus breaking the circular dependency. The second approach is to use the DIP (dependency inversion principle) and ISP (Interface Separation principle) design principles.

The acyclic dependency principle (ADP) solves the problem of relationship coupling between packages. When designing a module, there can be no circular dependencies.

This is the end of the content of "what are the principles of software design". Thank you for your reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report