Seven principles of OOP
- Opening and closing principle: open to extension and close to modification
- Richter substitution principle: inheritance must ensure that the properties owned by the superclass are still valid in the subclass
- Dependency Inversion Principle: interface oriented programming, not implementation oriented programming
- Single responsibility principle: control the granularity of classes, decouple objects and improve their cohesion
- Interface isolation principle: establish the special interface for each class they need
- Dimitri's Law: only talk to your direct friends, not strangers
- Synthesis Reuse Principle; Try to use the combination or aggregation relationship first, and then use the inheritance relationship
Factory mode
Core: instantiated objects do not use new, but use factory methods instead.
We will select real classes and create objects for unified management and control, so as to decouple our implementation classes
Three modes:
- Simple factory mode
It is used to produce any product in the same grade structure. Although it does not conform to the design principles to some extent, it is actually used most - Factory method model
It is used to produce fixed products in the same hierarchical structure. It can be expanded by adding new factories without modifying existing classes - Abstract factory pattern
Create other factories around a super factory, which is also called the factory of other factories
Application scenario
- getInstance() method of Calender in JDK
- connection object acquisition in JDBC
- Creating management bean objects in the IOC container in Spring
- CLass object newInstance method in reflection
Now suppose the customer wants to buy a car
public interface Car { //name void name(); }
public class TeSla implements Car{ @Override public void name() { System.out.println("This is Tesla"); } }
public class BaoMa implements Car{ @Override public void name() { System.out.println("This is BMW"); } }
Customers want to get a car, our normal way of thinking is new object and then call the method.
BaoMa baoMa=new BaoMa(); TeSla teSla=new TeSla(); baoMa.name(); teSla.name();
This seems a little cumbersome, and customers have to go to new, so we consider whether we can have a factory to do it for us
This seems OK, but if you think about it carefully, there will be new problems. Suppose we need another type of car and have to modify the code, which does not comply with the opening and closing principle of one of the seven principles, so let's improve our code.
public interface CarFactory { //Equivalent to a large automobile factory Car getCar(); }
Now what type of car do we want? We only need to implement the interface, and then write the method. We don't need to modify the code, but only need to expand horizontally.
Abstract factory pattern
- Definition: the abstract factory pattern provides an interface to create a series of related or interdependent objects without specifying their specific classes
- The client does not depend on the details of how the product class instance is created and implemented
- Emphasize that using a series of related product objects together requires a lot of repetitive code to create objects
- It provides a library of a series of products. All products appear with the same interface, so that the client does not depend on the specific implementation
Code demonstration
Now there are two factories, one responsible for the production of mobile phones and the other responsible for the production of routers
//The router factory is dedicated to the production of routers public interface RouterProduct { void open(); void close(); void setMs(); }
//The mobile phone factory specializes in producing mobile phones public interface phoneFactory { void open(); void sendMessage(); void close(); }
There is also a general factory responsible for the production of these two factories (it's a little abstract, so it's good to understand)
public interface FactoryAll { //Production of mobile phones phoneFactory phoneProduct(); //Production router RouterProduct routerProduct(); }
Now we want to produce a Huawei mobile phone and a Huawei router ok to realize the total factory interface
public class huaweiFactory implements FactoryAll{ @Override public phoneFactory phoneProduct() { return new huaweiPhone(); } @Override public RouterProduct routerProduct() { return new huaweiRouter(); } }
ok, now we can take the Huawei factory to produce Huawei products
- Huawei mobile phone
public class huaweiPhone implements phoneFactory{ @Override public void open() { System.out.println("Huawei mobile phone on"); } @Override public void sendMessage() { System.out.println("Huawei mobile phone sends information"); } @Override public void close() { System.out.println("Huawei mobile phone shutdown"); } }
- Huawei router
public class huaweiRouter implements RouterProduct{ @Override public void open() { System.out.println("Huawei router on"); } @Override public void close() { System.out.println("Huawei router off"); } @Override public void setMs() { System.out.println("Huawei router modification parameters"); } }
Simulated customer
public class Client { @Test public void getProduct(){ //Get factory huaweiFactory huaweiFactory=new huaweiFactory(); //Want the factory to produce mobile phones phoneFactory phoneFactory = huaweiFactory.phoneProduct(); //mobile phone phoneFactory.open(); phoneFactory.sendMessage(); phoneFactory.close(); //Want a router RouterProduct routerProduct = huaweiFactory.routerProduct(); //Router routerProduct.open(); routerProduct.setMs(); routerProduct.close(); } @Test public void buy(){ System.out.println("I want to see Huawei products"); getProduct(); } }
This is easier to understand. I want Huawei products, so all the products I get are produced by a Huawei factory.
But let's think about what to do if the customer wants to see Huawei robots. The manufacturer should not only add interface codes in the General Factory, but also add implementation classes, and will modify a lot of codes. Isn't that his disadvantage
proxy pattern
- Introduction:
For another example, the level of our king's glory is not enough, so we asked to call to help us play the game.
Let's start writing code now
There is an actor interface. The actor's duty is to play
public interface Actor { //Actors in movies void play(); }
Suppose the author is now a small fresh meat
public class jiaSen implements Actor{ @Override public void play() { System.out.println("jiaSen I want to play a memorable film"); } }
Now jiaSen has an agent
public class agent implements Actor{ private jiaSen jiaSen; public agent(jiaSen jiaSen){ this.jiaSen=jiaSen; } //Extra work done by the agent public void link(){ System.out.println("Economic man Gang jiaSen Contact the company to find the film"); } @Override public void play() { jiaSen.play(); link(); } }
jiaSen is popular in movies now, so the agent wants to increase the money, but Nah, jiaSen said yes, but on the premise that you can only be my agent now
Don't be anyone else's
After negotiation, the broker finally agreed
public agent(){ this.jiaSen=new jiaSen(); } //Add money public void addMoney(){ System.out.println("Add 1000 yuan"); }
The agent is transparent when others see it..
Dynamic agent
- However, the good times did not last long. The agent was too greedy. jiaSen felt that he was making less and less money. He wanted to find other agents and was afraid of being more greedy than this
- So jiaSen decided to plan his time reasonably and decide to be his economic man.
public static void main(String[] args) { jiaSen jiaSen=new jiaSen(); Actor proxyInstance = (Actor) Proxy.newProxyInstance(jiaSen.getClass().getClassLoader(), jiaSen.getClass().getInterfaces(), (proxy, method, args1) -> { if (method.getName().equals("play")){ method.invoke(jiaSen,args); System.out.println("jiaSen Take time to be your own agent"); }else{ return method.invoke(jiaSen,args); } return null; }); proxyInstance.play(); }
Let's read this code
- Java provides a Proxy class. Calling its newInstance method can generate a Proxy object of an object. This method requires three parameters
The difference between dynamic agent and static agent
- Static proxy needs to write its own proxy class = = > the proxy class and the proxy class implement the same interface
- Dynamic agents are generated dynamically through reflection mechanism
Disadvantages of static proxy:
- If there are many methods in the interface, it will be troublesome and cumbersome to implement each method
Advantages of dynamic agent
- The generation of proxy object is to use JDKAPI to dynamically build proxy object in memory, and will implement all methods of the interface by default