Six basic principles of design patterns
There are a lot of related content on the Internet, but most of them are too complicated. So here I want to use an article to summarize and summarize these six principles, some of the content in this article is taken from the Internet. Due to my limited level, errors are inevitable. If my personal understanding is wrong or not in place, please kindly advise.
1. Single Responsibility Principle (SRP: Single Responsibility Principle)
Key sentence:One class is only responsible for one responsibility
For example:
Class Animal {public void breathe (String animal) {System. out. println (animal + "breathing with lung") ;}} public class Client {public static void main (String [] args) {Animal animal = new Animal (); animal. breathe ("Ox"); animal. breathe ("goat"); animal. breathe ("pig ");}}
The running results do not need to be said much, but we will find that this Animal class will also include fish and animal. breathe ("fish"), apparently the common fish do not breathe through the lungs, then we need to modify it.Responsibilities spread here. Due to some reason, responsibilities need to be divided into Responsibilities 1 and 2.
We may change it like this:
(1) modify the breathe method of the Animal class: (the modification method is not recommended)
Public void breathe (String animal) {if ("fish ". equals (animal) {System. out. println (animal + "breathing with gill");} else {System. out. println (animal + "breathing with lung ");}}
The above modification method is very simple, but there are further risks. If we know that some fish will breathe in other ways one day, we need to further modify this class, at this time, our changes may affect the way cattle and sheep breathe. This also violates the single responsibility principle, so this method is not advisable.
(2) Add a new breathe method for the Animal class: (determine whether to use it based on the actual situation)
Class Animal {public void breathe (String animal) {System. out. println (animal + "breathing with lung");} public void breathe2 (String animal) {System. out. println (animal + "breathing with gill ");}}
The above modification method conforms to the single responsibility principle at the method level because it does not touch the code of the original method. Class level violates the single responsibility principle. This method can be used when there are few methods in the class.
(3) subdivided Animal class: (standard, not in violation of a single responsibility)
Class Terrestrial {public void breathe (String animal) {System. out. println (animal + "breathing with lung");} class Aquatic {public void breathe (String animal) {System. out. println (animal + "breathing with gill ");}}
In the above modification method, the modification cost is very large. In addition to decomposing the original Animal class, you also need to modify the client. That is:
Terrestrial terrestrial = new Terrestrial (); terrestrial. breathe (""); Aquatic aquatic = new Aquatic (); aquatic. breathe (" ");
Therefore, the above (2) (3) modification method needs to be integrated with the complexity of the project and so on (how to choose to use it as mentioned above)
2. Lean replacement Principle (LSP: Liskov Substitution Principle)
Key sentence:Sub-classes can extend the functions of the parent class, but cannot change the original functions of the parent class.
This principle is mainly for inheritance, because inheritance often has the following meaning: The methods implemented in the parent class are actually descriptions and definitions of some behaviors of this class. If the subclass modifies this method randomly, the inheritance system will be damaged.
In actual programming, we often rewrite the parent class method to complete new functions. Although the writing is simple, the code reusability of the entire inheritance system is poor.
If you want to override the parent class method, the general practice is: the original parent class and subclass inherit a more popular base class, the original inheritance relationship is removed, using dependency, aggregation, replace links such as combinations.
3. Dependency Inversion Principle (DIP: Dependency Inversion Principle)
Key sentence:Details should depend on abstraction, interface-Oriented Programming
Let's look at the example to understand this principle:
Class Book {public String getContent () {return "A long time ago there was an Arabic story ...... ";}} Class Mother {public void narrate (Book book) {System. out. println ("Mom starts telling stories"); System. out. println (book. getContent () ;}} public class Client {public static void main (String [] args) {Mother mother = new Mother (); mother. narrate (new Book ());}}
In the above example, a Mother class has a Book class, and the Book class is passed into the Mother class as a parameter. In this way, the Mother class completes reading the Book class.
But at this time, we need to add a demand. Mother wants to read newspapers, similar to the Book class. The Newspaper class is as follows:
Class Newspaper {public String getContent () {return "Jeremy Lin 38 + 7 leads the Knicks to defeat the Lakers ...... ";}}
At this time, we found that the narrate method of the Mother class only accepts Book objects and does not read Newspaper. Therefore, we consider the following modification method:
(1) Add the narrate1 Method to the Mother class and pass in Newspaper.
It is an absolute design. If there are other magazines and novels to read in the future, will there be more methods to be added, and the Mother class should be constantly modified.
(2) introduce the IReader interface for interface programming.
interface IReader{ public String getContent(); }
The Mother class is dependent on the IReader interface, while both Book and Newspaper belong to the category of reading books. They implement the IReader interface respectively, so that they conform to the dependency inversion principle and the code is changed:
Class Newspaper implements IReader {public String getContent () {return "Lin shuhao 17 + 9 help the Knicks defeat the hawks ...... ";}} Class Book implements IReader {public String getContent () {return" A long time ago there was an Arabic story ...... ";}} Class Mother {public void narrate (IReader reader) {System. out. println ("Mom starts telling stories"); System. out. println (reader. getContent () ;}} public class Client {public static void main (String [] args) {Mother mother = new Mother (); mother. narrate (new Book (); mother. narrate (new Newspaper ());}}
Following the Dependency inversion principle can reduce coupling between classes, improve system stability, and reduce risks caused by program modification.
4. Interface isolation principle (ISP: Interface Segregation Princeple)
Key sentence:The client should not rely on the interface it does not need; the dependency of one class on the other class should be built on the smallest Interface
This principle solves the following problem:
Class A relies on Class B through interface I, and class C relies on Class D through the same interface I. This is the method for interface I to have class B and class D, but for class B and class D they do not need each other's method. In this case, the interface I is too bloated and therefore needs to be split.
This principle is easy to understand. Examples are not used here. Remember thatTo create a single interface, do not create a large and bloated interface, and moderately refine the interface. The interface should contain as few methods as possible.
5. Law of Demeter/LKP: Least Knowledge Principle)
Key sentence:An object should have a minimum understanding of other objects and minimize the coupling between classes.
This principle can also be understood in this way, the class only communicates with direct friends. (Direct friends include: member variables, method parameters, and method return values)
For example, the following program is available:
// Class Employee {private String id; public void setId (String id) {this. id = id;} public String getId () {return id ;}// class SubEmployee {private String id; public void setId (String id) {this. id = id;} public String getId () {return id ;}}
Now we need to output the Id of the entire company employee. We may write the code like this:
Class SubCompanyManager {public List
GetAllEmployee () {List
List = new ArrayList
(); For (int I = 0; I <100; I ++) {SubEmployee emp = new SubEmployee (); // assign an ID emp to the Branch staff in sequence. setId ("branch" + I); list. add (emp) ;}return list ;}} class CompanyManager {public List
GetAllEmployee () {List
List = new ArrayList
(); For (int I = 0; I <30; I ++) {Employee emp = new Employee (); // assign an ID emp to the Headquarters personnel in sequence. setId ("Head Office" + I); list. add (emp) ;}return list;} public void printAllEmployee (SubCompanyManager sub) {List
List1 = sub. getAllEmployee (); for (SubEmployee e: list1) {System. out. println (e. getId ();} List
List2 = this. getAllEmployee (); for (Employee e: list2) {System. out. println (e. getId ());}}}
Create the getAllEmployee () method in the SubCompanyManager class of the Branch ()
Create Methods getAllEmployee () and printAllEmployee () in the company CompanyManager class ().
According to the dimit rule, ComanyManager and Employee are direct friends, but they are not direct friends with SubEmployee. In this way, the company and the branch are logically coupled. Therefore, this method is not desirable and needs to be modified:
Class SubCompanyManager {public List
GetAllEmployee () {List
List = new ArrayList
(); For (int I = 0; I <100; I ++) {SubEmployee emp = new SubEmployee (); // assign an ID emp to the Branch staff in sequence. setId ("branch" + I); list. add (emp) ;}return list;} public void printEmployee () {List
List = this. getAllEmployee (); for (SubEmployee e: list) {System. out. println (e. getId () ;}} class CompanyManager {public List
GetAllEmployee () {List
List = new ArrayList
(); For (int I = 0; I <30; I ++) {Employee emp = new Employee (); // assign an ID emp to the Headquarters personnel in sequence. setId ("Head Office" + I); list. add (emp) ;}return list;} public void printAllEmployee (SubCompanyManager sub) {sub. printEmployee (); List
List2 = this. getAllEmployee (); for (Employee e: list2) {System. out. println (e. getId ());}}}
The above method effectively reduces the coupling between classes and only communicates with direct friends.
6. Open and Close Principle (OCP: Open Closed Principle)
Key sentence:Classes, modules, and functions should be open to extensions and closed for modifications
In the open/closed principle, "open" means that the component functions are open and can be extended;
In the open and closed principle, "closed" means that the modification to the original code is closed, that is, the original code should not be modified.
As mentioned above, the Lishi replacement principle, the dependency inversion principle, the interface isolation principle, and the abstract classes and interfaces we know can all be seen as the implementation method of the open and closed principles.