This is the first day of my participation in Gwen Challenge
The characteristics of Java language are encapsulation, polymorphism and inheritance. Design pattern is the solution of various business scenarios based on this feature
The purpose of using design patterns is to make our software better
- Code reuse (you don’t have to write the same code more than once)
- Readability (coding is normative and easy for other programmers to read and understand)
- Scalability (easy to add new features)
- Reliability (when we add new functions, the original functions are not affected)
- Make the program appear high cohesion, low coupling
Application of Design Pattern in Software Development: Oop => Functional module design (Design pattern + algorithm) => Framework (multiple design patterns) => Architecture (service cluster)
Seven principles of design patterns
- Single responsibility principle
- Interface Isolation Principle
- Rely on the inversion principle
- Richter’s substitution principle
- The open closed principle
- Demeter principle
- Principle of composite reuse
Single responsibility principle:
A class should have only one responsibility, but not only one method
Interface isolation rules:
The client should not rely on the interface it does not need, that is, the dependency of one class on another class should be established on the smallest interface. For example: In actual production, the dependency relationship between interfaces is complicated, which will produce the problem of circular dependency
Rely on the inversion principle
- High-level modules should not depend on low-level modules; both should depend on abstractions
- Abstractions should not depend on details, details should depend on abstractions
- The central idea of dependency inversion is interface oriented programming
In Java, abstraction refers to an interface or abstract class, and detail refers to a concrete implementation class
Sample business requirements
To achieve mobile phone receive wechat receive mail function
Negative case:
Define mail functionality
class Email0{
public String getInfo(){
return "Email0: hello!";
}
}
Copy the code
Define wechat functions
class Weixin0{
public String getInfo(){
return "Weixin0: hello!";
}
}
Copy the code
Define mobile phone to realize the function of receiving email and wechat
class Phone{ public void recieve(Email0 email0){ System.out.println(email0.getInfo()); } public void recieveWeixin(Weixin0 weixin0){ System.out.println(weixin0.getInfo()); }}Copy the code
Define client using mobile phone
public class DependenceInversion { public static void main(String[] args) { new Phone().recieve(new Email0()); new Phone().recieveWeixin(new Weixin0()); }}Copy the code
The above method also works but the code looks bloated and difficult to maintain. If the function of receiving SMS is added now, you need:
- Define the SMS function
- Mobile phones can receive SMS messages
- The client invokes the SMS receiving method using the mobile phone
In the second step, it violates the principle of dependency reversal. The high-level part directly depends on the underlying module, and the details depend on the details. The complex business logic is not supported by the abstraction layer.
Optimization: Define abstraction layer “receive information” each part function realization abstraction layer write corresponding function logic mobile phone function depends on abstraction layer client define mobile phone to realize corresponding function according to its own demand
Optimized code
Defines the interface
interface Ireceiver{
String getInfo();
}
Copy the code
Define the mail function implementation interface
Class Email implements Ireceiver{@override public String getInfo() {return "Email implements Ireceiver "; }}Copy the code
Define wechat function implementation interface
Class Weixin implements Ireceiver{@override public String getInfo() {return "Weixin implements Ireceiver "; }}Copy the code
Defining a mobile phone relies on an abstraction layer
class Person{ public void receive(Ireceiver ireceiver){ System.out.println(ireceiver.getInfo()); }}Copy the code
Define different mobile phone functions used by the client
public class DependenceInversion1 { public static void main(String[] args) { Person person=new Person(); person.receive(new Email()); person.receive(new Weixin()); }}Copy the code
Dependencies can be passed in three ways:
Sample business requirements:
There is a player player that needs to use the play method in the ITV interface class
As interface
ITV interface
interface ITV{
public void play();
}
Copy the code
Player interface
interface IPlayer{
public void open(ITV itv);
}
Copy the code
Player class
class Player implements IPlayer{ @Override public void open(ITV itv) { itv.play(); }}Copy the code
Constructor pass
ITV interface
interface ITV2{
public void play();
}
Copy the code
Player interface
interface IPlayer2{
public void open();
}
Copy the code
Player class
class Player2 implements IPlayer2{ public ITV2 tv; public Player2(ITV2 tv){ this.tv=tv; } @Override public void open() { this.tv.play(); }}Copy the code
Setter pass
ITV interface
interface ITV3{
void play();
}
Copy the code
Player interface
interface Player3{
void open();
}
Copy the code
Player class
class Player3 implements IPlayer3{ private ITV3 tv; public void setTv(ITV3 tv) { this.tv = tv; } @Override public void open() { this.tv.play(); }}Copy the code
Rely on reverse details
- Low-level modules should have abstract classes or interfaces, or both, for better program stability.
- Variables are declared as abstract classes or interfaces as possible, so that there is a buffer layer between our variable reference and the actual object, which is convenient for program expansion and optimization.
- Inheritance follows the Richter substitution principle.
So for the time being, let’s talk about the Richter substitution principle in the next canto