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 six principles of Java design pattern

2025-03-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

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

This article mainly explains "what are the six principles of Java design pattern". The content of the explanation is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn what the six principles of Java design pattern are.

1. Principle of single responsibility

Single responsibility definition

A class is only responsible for the corresponding responsibilities in a functional area, or it can be defined as: as far as a class is concerned, there should be only one reason for its change.

It is not difficult to think from the definition, the more things a class does, the more difficult it is to reuse, because once more things are done, the coupling of responsibilities becomes higher, so we should package different responsibilities in different categories according to this principle. Different changes are encapsulated in different categories. From our usual development, it is not difficult to find that if a class or method interface and so on only do one thing, then it is highly readable and reusable, and once the requirements change, it is also easy to maintain, if you have a class mixed with multiple responsibilities, so it's hard to maintain.

An example Analysis of a single responsibility

To spin off an example from the actual business: now there is a situation where the personal module class of a car rental platform involves multiple methods. There are the following login, registration, Alipay deposit payment, Wechat deposit payment, Alipay package payment, Wechat package payment, the whole structure is as follows:

/ * personal module * / @ Controller public class userController {/ * login * / public void login () {} / * register * / public void register () {} / * deposit payment (Ali) * / public void payAliDeposit () {} / * deposit payment (Wechat) * / public void payWXDeposit () {} / * set Meal payment (Ali) * / public void payAliPackage () {} / * * package payment (Wechat) * / public void payWXPackage () {}}

We can see that many functions are mixed together. A class has done so many things, it is very bloated, not to mention maintenance, and it is very difficult to find the code, so we can disassemble the UserController. At the same time, we should subcontract, for example, this should be under the xxx.xxx.userMoudule, there may be public methods related to payment, login or public methods, and the public service should be extracted to call there.

Public class LoginController () {} public class registerController () {} public class depositPayController () {/ / Alipay / / WeChat Pay} public class packagePayController () {/ / Alipay / / WeChat Pay}

The purpose of the whole scheme is to solve the problem of high coupling and low code reuse rate. A single responsibility is not difficult to understand, but the actual operation needs to be cut according to the mixing degree of the specific business, which is actually very difficult to use.

two。 Opening and closing principle

Brief introduction of opening and closing principle

The opening and closing principle is the first cornerstone of object-oriented reusable design, and it is the most important object-oriented design principle, which is defined as follows:

A software entity should be open to extensions and closed to modifications. That is, software entities should be extended as far as possible without modifying the original code.

The software entity consists of the following parts:

A module in a project or software product divided according to certain logical rules.

Abstractions and classes

Method

Note: the opening and closing principle means that it is open to extension and closed to modification, it does not mean that no changes are made.

Advantages of the principle of opening and closing

You can make the original test code still run, you only need to test the extended code

Can improve the reusability of the code

Can improve the maintainability of the system

How to use the principle of opening and closing

Abstract constraint

Limit the boundary of the extension through the interface or abstract class constraint extension, and do not allow public methods that do not exist in the interface or abstract class.

Parameter types and reference objects try to use interfaces or abstract classes rather than implementation classes; (programming for abstractions)

The abstraction layer is as stable as possible, and once determined, modification is not allowed.

Metadata control module behavior

Generally speaking, it is to manipulate data through configuration files, and the control inversion of spring is a typical example.

Convention is better than configuration

Encapsulation change

Encapsulate the same changes in an interface or class

Encapsulate different changes into different classes or interfaces (embodiment of a single responsibility)

Case

The car rental system developed by a company has a deposit payment function, and the payment methods include Alipay, Ali payment, UnionPay payment, easy payment and so on. The original design is as follows:

/ / client call-Deposit payment Select payment method public class DepositPay {void pay (String type) {if (type.equals ("ali")) {AliPay aliPay = new AliPay (); aliPay.pay ();} else if (type.equals ("wx")) {WXPay wxPay = new WXPay (); wxPay.pay ();} / / Alipay public class AliPay {public void pay () {System.out.println ("using Alipay") }} / / WeChat Pay public class WXPay {public void pay () {System.out.println ("using WeChat Pay");}}

In the above code, if you need to add UnionPay, such as YLPay, you must modify the source code of the pay method in DepositPay to add new judgment logic, which violates the opening and closing principle (closed for modification, open to extension, note that UnionPay payment here is equivalent to extension, so it does not violate the rules), so now you must reconstruct this code to follow the opening and closing principle, as follows:

Add an interface to enable various specific payments to implement their interfaces

The DepositPay class is programmed against the interface, and it is up to the client to decide which payment method to use

The refactored figure is as follows:

In the figure above, we introduce the interface Pay and define the pay method, and DepositPay is programmed against the interface, the specific payment method is instantiated by the client through setPayMode (), and the payMode object is called in the pay () method of DepositPay to pay. If you need to add a new payment method, such as UnionPay, you only need to allow it to implement the Pay API and configure UnionPay in the configuration file. Dependency injection is a means to implement this open / closed principle. The source code is as follows:

Public interface Pay {/ / pay void pay ();} public class AliPay implements Pay {@ Override public void pay () {System.out.println ("using Alipay");}} public class WXPay implements Pay {@ Override public void pay () {System.out.println ("using WeChat Pay") } / / client call-Deposit payment option payment method public class DepositPay {/ / payment method can be injected through dependency injection / / payment method can be written in the configuration file / / now no matter which method you choose, I don't need to change @ Autowired Pay payMode; void pay (Pay payMode) {payMode.pay ();}}

Because the configuration file can be edited directly and does not need to be compiled, changing the configuration file is not generally considered to be a change to the source code. If a system only needs to modify the configuration file and does not need to modify the source code, then the compound opening and closing principle.

3. Richter's substitution principle

A brief introduction to the principle of Richter scale substitution

Barbara Liskov proposed:

Standard definition: if for every object o1 of type S, there is an object o2 of type T, so that when all program P defined by T replaces o2 with all objects o1, the behavior of program P does not change, then type S is a subtype of type T.

The above definition may be difficult to understand, simply that all references to the base class (parent class) can be replaced with subclasses, and the program will not have any exceptions. But not the other way around. All places where subclasses are used may not be replaced by base classes. In a very simple example, dogs are animals, and animals cannot be said to be dogs, because there may be cats.

The Richter substitution principle is one of the important ways to realize the opening and closing principle. Because all places where the base class is used can be replaced by subclasses, we try to use the base class to define the object and determine its subclass type at run time.

Constraint of Richter scale substitution principle

Subclasses must implement the abstract methods of the parent class, but must not override (override) the non-abstract (implemented) methods of the parent class.

A unique method can be added to a subclass (which does not exist in the parent class), and it cannot be used in an object defined by the parent class unless the base class is strongly converted into a subclass when in use.

When a subclass overrides or implements a method of the parent class, the precondition (that is, the formal parameter of the method) of the method is looser than the input parameters of the parent method.

When the method of the subclass implements the abstract method of the parent class, the postcondition of the method (that is, the return value of the method) is more stringent than the parent class.

So when we apply the Richter substitution principle, we try our best to design the parent class as an abstract class or interface, so that the subclass inherits the parent class or implements the interface and implements the methods declared in the parent class. At run time, the subclass instance replaces the parent class instance. We can easily expand the function of the system without modifying the code of the original subclass. Adding new functions can be achieved by adding a new subclass. The principle of Richter scale substitution is one of the concrete means to realize the principle of opening and closing.

The principle of Richter scale replacement

A car rental system customer is divided into ordinary user (customer) and VIP customer (VIPCustomer). The system needs to provide a function to reset the password according to the mailbox. Original blueprints:

When writing the reset password, it is found that the business logic is the same, there is a lot of repetitive code, and new user types may be added. To reduce code repetition, ReFactor using the Richter substitution principle:

The reset password on the figure is handled by the ResetPassword class. You only need to pass in the Customer class. Any type of Customer class, as long as it inherits from Customer, can be replaced using the Richter replacement principle. If there is a new type, we just need to inject a new type into the configuration file. The code is as follows (a brief understanding):

/ / the abstract base class public abstract class Customer {} public class CommonCustomer extends Customer {} public class VIPCustomer extends Customer {} / / reset password logic is implemented here. You only need to pass in the corresponding type to public class ResetPassword {void resetPassword (Customer customer) {}}.

The Richter substitution principle is one of the indispensable means to realize the opening and closing principle. In this case, the base class object is used by passing parameters, and the abstract programming is used to satisfy the opening and closing principle.

4. Dependence reversal principle

A brief introduction to the principle of dependency inversion

Dependency inversion principle (Dependency Inversion Principle, DIP): abstractions should not depend on details, which should depend on abstractions. In other words, program against the interface, not against the implementation.

It can be popularly defined in two ways:

High-level modules should not rely on low-level modules, they should all rely on abstraction.

Abstraction should not depend on concrete implementations, which should depend on abstractions.

We are required to use high-level abstract classes as far as possible when designing programs, even if we use interfaces and abstract classes for variable declaration, parameter type declaration, method return type declaration, data type conversion and so on. At the same time, it should be noted that a concrete class should only implement the abstract class or the methods that exist in the interface, and do not give redundant methods, so that the abstract class will not be able to call the methods added by the subclass. We can write specific classes through the configuration file, so that once the program behavior changes, we can directly change the configuration file without changing the program, recompile, and satisfy the opening and closing principle by relying on the inversion principle.

When implementing the principle of dependency inversion, we need to program for the abstract layer and inject the objects of concrete classes into other objects by means of DependencyInjection (DI). Dependency injection means that when an object has a dependency with other objects, it injects the dependent objects through abstraction. There are three common injection methods, namely: construction injection, set value injection (Setter injection) and interface injection.

An example of the principle of dependency inversion

In this part, we can refer to the case of the opening and closing principle above, and we can see from that example that the opening and closing principle, relying on the inversion principle, and the Richter replacement principle appeared at the same time. It can be said that the opening and closing principle is the goal that we want to achieve, and the Richter replacement principle is one of the means to achieve it, and at the same time, the Richter substitution principle is the basis for relying on the inversion principle, because without this theory, relying on the inversion principle is not established. It is impossible to program against abstraction, so it is important to note that these three principles are basically simultaneous. Java back-end learning communication circle: 834962734 for 2-6 years of Java developers, you can get a free Java architecture advanced technology video. (high concurrency + Spring source code + JVM principle analysis + distributed architecture + micro-service architecture + multithreaded concurrency principle + BATJ interview treasure book) and architecture mind map.

5. Interface isolation principle

Brief introduction to the principle of Interface isolation

Two definitions of the principle of interface isolation:

1: use multiple specialized interfaces instead of a single master interface, that is, the client should not rely on interfaces it does not need

2: dependencies between classes should be based on the smallest interface

The meaning of the interface:

An interface represents a role, and different roles should not be assigned to one interface, because this may lead to a bloated interface.

A language-specific interface, indicating that the interface only provides the behavior that the client needs, while the behavior that the client does not need is hidden, and the client should be provided with a separate interface as small as possible, rather than a large total interface.

According to the principle of interface isolation, we can understand that each interface should play a relatively independent role and should not do anything that should not be done.

Example demonstration

Scene: simulate the normal movements of animals, including people, of course, the original design is a general interface IAnimal, which defines some of the actions that animals will have.

The code is as follows:

Public interface IAnimal {/ * eat * / void eat (); / * work * / void work (); / * fly * / void fly ();} public class Tony implements IAnimal {@ Override public void eat () {System.out.println ("tony eat");} @ Override public void work () {System.out.println ("tony work") } @ Override public void fly () {System.out.println ("tony can't fly");}} public class Bird implements IAnimal {@ Override public void eat () {System.out.println ("bird eating");} @ Override public void work () {System.out.println ("bird work");} @ Override public void fly () {System.out.println ("bird fly");}}

According to the above writing, it is found that Tony needs to implement the flying interface, which is obviously not only superfluous, but also unreasonable, so it needs to be reconstructed by the principle of interface isolation:

/ * Abstract animal behavior * / public interface IAnimal {/ * eat * / void eat (); / * sleep * / void sleep ();} / * * higher animal human behavior * / public interface IAdvancedAnimalBehavior {/ * playing cards * / void playCard (); / * cycling * / void byBike () Behavior of low-level animals * / public interface IJuniorAnimalBehavior {/ * fly * / void fly ();} / * implement the common method of higher animal humans * / public class AbstractAdvancedAnimal implements IAnimal {@ Override public void eat () {System.out.println ("people eat");} @ Override public void sleep () {System.out.println ("people sleep") Public class AbstractJuniorAnimal implements IAnimal {@ Override public void eat () {System.out.println ("animal eating");} @ Override public void sleep () {System.out.println ("animal sleep");} / tonypublic class Tony extends AbstractAdvancedAnimal implements IAdvancedAnimalBehavior {@ Override public void playCard () {System.out.println ("tony playing cards") } @ Override public void byBike () {System.out.println ("tony cycling");} / / public class Bird extends AbstractJuniorAnimal implements IJuniorAnimalBehavior {@ Override public void fly () {System.out.println ("Bird Flying");}}

After refactoring, a large class of general animal interface is defined, and then two abstract classes (one is high-level animal and the other is low-level animal) are used to implement these common methods respectively, and an exception can be thrown in the implementation. it indicates that the class that inherits this abstract class can be selectively rewritten, but not rewritten. After that, two behavioral interfaces are defined to show that the interfaces are unique to high-level animals and low-level animals, so that the interfaces are completely isolated, and the animal interfaces are no longer mixed with various roles. Of course, the size of the interface still has to be adjusted by experience. It can not be too small, it will cause interface flooding, and it will deviate from the principle of interface isolation.

6. Principle of synthetic reuse

A brief introduction to the principle of synthetic reuse

Synthetic reuse principle (Composite Reuse Principle, CRP): try to use object composition rather than inheritance to achieve the purpose of reuse.

Through the principle of synthetic reuse to make some existing objects part of the object, generally through the composition / aggregation relationship, and try not to use inheritance. Because composition and aggregation can reduce the coupling between classes, and inheritance will make the system more complex, the most important point will destroy the encapsulation of the system, because inheritance will expose the implementation details of the base class to the subclass, and if the base class changes, the subclass must also change, and the coupling degree will be very high.

Thank you for your reading, the above is the content of "what are the six principles of Java design pattern". After the study of this article, I believe you have a deeper understanding of what the six principles of Java design pattern are, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

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