Why design patterns
Purpose of design pattern
- Code reusability (code with the same function does not need to be written multiple times)
- Readability (programming is normative and easy for other programmers to read and understand)
- Scalability (it can be easily implemented when new functions need to be added)
- Reliability (when a new function is added to the system, it will not affect the operation of the original function)
- Make the program show the characteristics of high cohesion and low coupling (the interior of the module is highly cohesive and compact, but the coupling between modules and functions is low)
Importance of design patterns
-
In the 1990s, it was introduced into computer science from the field of architectural design. The so-called design pattern is a solution to various problems that are common (recurring) in software design
-
In practical work, the demand for adding new functions is relatively common. Design patterns are very important for the scalability (one of the main problems to be solved by design patterns), maintainability and readability of the project
-
Where do design patterns appear in the software?
Object oriented (OOP) = > function module [design pattern + algorithm (data structure)] = > framework [using multiple design patterns] = > Architecture [server cluster] -
Design patterns often consider problems from the perspective of overall software design. For example, they need to consider the maintainability and expansibility of software. They do not think about problems from the perspective of function realization, so the solutions to some simple problems will be more complex than we usually think.
Seven design principles
Single responsibility principle
1. Definition: do not have more than one reason for class change. For classes, that is, a class should be responsible for only one responsibility.
2. Examples
(1)demo1
/** * @ClassName: demo1 * @Description: Single responsibility principle, mode 1 * @Author:csq * @Date 2021/12/29 * @Version 1.0 **/ public class demo1 { public static void main(String[] args) { Vehicle vehicle = new Vehicle(); vehicle.run("motorcycle"); vehicle.run("Cycling"); vehicle.run("aircraft"); } } // Vehicles // Mode 1 // 1. In the run method of mode 1, the principle of single responsibility is violated because the aircraft cannot operate on the road // 2. The solution is very simple. It can be decomposed into different types according to different operation methods of vehicles class Vehicle{ public void run(String vehicle){ System.out.println(vehicle + "Running on the highway..."); } }
(2)demo2
/** * @ClassName: demo2 * @Description: Single responsibility principle: mode 2 * @Author:csq * @Date 2021/12/29 * @Version 1.0 **/ public class demo2 { public static void main(String[] args) { RoadVehicle roadVehicle=new RoadVehicle(); roadVehicle.run("motorcycle"); AirVehicle airVehicle=new AirVehicle(); airVehicle.run("aircraft"); SeaVehicle seaVehicle=new SeaVehicle(); seaVehicle.run("ship"); } } //Analysis of scheme 2 //1. Abide by the principle of single responsibility //2. However, the change is very big, that is, the class is decomposed and the client is modified at the same time //3. Improvement: modify the Vehicle class directly, and the changed code will be less = > scheme 3 class RoadVehicle{ public void run(String vehicle){ System.out.println(vehicle+"Running on the highway"); } } class AirVehicle{ public void run(String vehicle){ System.out.println(vehicle+"Running in the sky"); } } class SeaVehicle{ public void run(String vehicle){ System.out.println(vehicle+"Running in water"); } }
(3)demo3
/** * @ClassName: demo3 * @Description: Option 3 * @Author:csq * @Date 2021/12/29 * @Version 1.0 **/ public class demo3 { public static void main(String[] args) { // TODO Auto-generated method stub Vehicle2 vehicle2 = new Vehicle2(); vehicle2.run("automobile"); vehicle2.runWater("ship"); vehicle2.runAir("aircraft"); } } //Analysis of mode 3 //1. This modification method does not greatly modify the original class, but only adds methods //2. Although the principle of single responsibility is not observed at the class level, it is still observed at the method level class Vehicle2 { public void run(String vehicle) { //handle System.out.println(vehicle + " Running on the highway...."); } public void runAir(String vehicle) { System.out.println(vehicle + " Running in the sky...."); } public void runWater(String vehicle) { System.out.println(vehicle + " Walk in the water...."); } //If there are multiple methods, this approach is not desirable. When there are many methods, you still need to divide them into multiple classes }
3. Precautions and details
- Reduce the complexity of classes. A class is responsible for only one responsibility.
- Improve the readability and maintainability of classes
- Reduce risks caused by changes
- Generally, we should abide by the principle of single responsibility. Only when the logic is simple enough can we violate the principle of single responsibility at the code level; Only the number of methods in the class is small enough to maintain the principle of single responsibility at the method level
Interface isolation principle
1. Definition: the client should not rely on interfaces it does not need. The dependence of one class on another should be based on the smallest interface.
2. Example:
- Interface isolation principle not implemented:
public class Segregation1 { public static void main(String[] args) { // TODO Auto-generated method stub } } //Interface interface Interface1 { void operation1(); void operation2(); void operation3(); void operation4(); void operation5(); } class B implements Interface1 { public void operation1() {System.out.println("B Realized operation1");} public void operation2() {System.out.println("B Realized operation2");} public void operation3() {System.out.println("B Realized operation3");} public void operation4() {System.out.println("B Realized operation4");} public void operation5() {System.out.println("B Realized operation5");} } class D implements Interface1 { public void operation1() {System.out.println("D Realized operation1");} public void operation2() {System.out.println("D Realized operation2"); } public void operation3() {System.out.println("D Realized operation3");} public void operation4() {System.out.println("D Realized operation4");} public void operation5() {System.out.println("D Realized operation5");} } class A { //Class A relies on (uses) class B through interface Interface1, but only 1,2,3 methods are used. // Then the 4 and 5 methods in class B may be written in vain public void depend1(Interface1 i) {i.operation1();} public void depend2(Interface1 i) {i.operation2();} public void depend3(Interface1 i) {i.operation3();} } class C { //Class C relies on (uses) class D through interface Interface1, but only uses methods 1, 4 and 5 //Then the 4 and 5 methods in class D may be written in vain public void depend1(Interface1 i) {i.operation1();} public void depend4(Interface1 i) {i.operation4();} public void depend5(Interface1 i) {i.operation5();} } //According to the principle of isolation, it should be handled as follows: //Split interface Interface1 into several independent interfaces, //Class A and class C establish dependencies on the interfaces they need. That is, the principle of interface isolation is adopted
- The uml diagram in this example is as follows:
- The principle of interface isolation is realized
public class Segregation1 { public static void main(String[] args) { // TODO Auto-generated method stub // Use one A a = new A(); a.depend1(new B()); // Class A depends on class B through the interface a.depend2(new B()); a.depend3(new B()); C c = new C(); c.depend1(new D()); // Class C relies on (uses) class D through the interface c.depend4(new D()); c.depend5(new D()); } } // Interface 1 interface Interface1 {void operation1();} // Interface 2 interface Interface2 {void operation2();void operation3();} // Interface 3 interface Interface3 {void operation4();void operation5();} class B implements Interface1, Interface2 { public void operation1() {System.out.println("B Realized operation1");} public void operation2() {System.out.println("B Realized operation2");} public void operation3() {System.out.println("B Realized operation3");} } class D implements Interface1, Interface3 { public void operation1() {System.out.println("D Realized operation1");} public void operation4() {System.out.println("D Realized operation4");} public void operation5() {System.out.println("D Realized operation5");} } class A { // Class A passes through interface interface1 and interface2 depend on (use) class B, but only methods 1, 2 and 3 are used public void depend1(Interface1 i) {i.operation1();} public void depend2(Interface2 i) {i.operation2();} public void depend3(Interface2 i) {i.operation3();} } class C { // Class C relies on (uses) class D through interface interface1 and interface3, but only uses methods 1, 4 and 5 public void depend1(Interface1 i) {i.operation1();} public void depend4(Interface3 i) {i.operation4();} public void depend5(Interface3 i) {i.operation5();} }
- Its UML diagram is