This is my third article about getting started
1. Introduction to design patterns
1.1 introduction
Design patterns represent best practices and are generally adopted by experienced object-oriented software developers. Design pattern is a solution to the common problems faced by software developers during software development. These solutions have been developed by numerous software developers over a long period of trial and error. A design pattern is a set of repeated, well-known, catalogued code design lessons. Design patterns are used to reuse code, make it easier for others to understand, and ensure code reliability. There is no doubt that design patterns are a win-win for yourself, others and systems. Design patterns make coding truly engineering. Design patterns are the cornerstones of software engineering, like the bricks and stones of a mansion. The rational application of design patterns in projects can perfectly solve many problems. Each pattern has its corresponding principle in reality, and each pattern describes a recurring problem around us, as well as the core solution of the problem, which is also the reason why design patterns can be widely used.
1.2 Types of design patterns
There are 23 Design Patterns in all, according to the reference book Design Patterns – Elements of Reusable Object-oriented Software. These Patterns fall into three broad categories: Creational Patterns, Structural Patterns, and Behavioral Patterns. Of course, we’ll also discuss another class of design patterns: the J2EE design pattern.
1.2.1 Creator mode
These design patterns provide a way to hide the creation logic while creating objects, rather than instantiating objects directly using the new operator. This gives the program more flexibility in deciding which objects to create for a given instance.
- Factory Pattern
- Abstract Factory Pattern
- Singleton Pattern
- Builder Pattern
- Prototype Pattern
1.2.2 Structural mode
These design patterns focus on combinations of classes and objects. The concept of inheritance is used to combine interfaces and define how composite objects acquire new functionality.
- Adapter Pattern
- Bridge Pattern
- Filter Pattern (Filter, Criteria Pattern)
- Composite Pattern
- Decorator Pattern
- Facade Pattern
- Flyweight Pattern
- Proxy Pattern
1.2.3 Behavioral patterns
- Chain of Responsibility Pattern
- Command Pattern
- Interpreter Pattern
- Iterator Pattern
- Mediator Pattern
- Memento Pattern
- Observer Pattern
- State Pattern
- Null Object Pattern
- Strategy Pattern
- Template Pattern
- Visitor Pattern
1. J2EE patterns
- MVC Pattern (MVC Pattern)
- Business Delegate Pattern
- Composite Entity Pattern
- Data Access Object Pattern
- Front Controller Pattern
- Intercepting Filter Pattern
- Service Locator Pattern
- Transfer Object Pattern
1.3 Six principles of design Patterns
1.3.1 Open Close Principle
The open closed principle means: open for extensions, closed for modifications. When the program needs to be extended, you cannot modify the original code to achieve a hot plug effect. In short, to make the program extensible, easy to maintain and upgrade. To achieve this, we need to use interfaces and abstract classes, which will be discussed later in the concrete design.
1.3.2 Liskov Substitution Principle
Richter’s substitution principle is one of the basic principles of object-oriented design. Richter’s rule of substitution says that wherever a base class can appear, a subclass must appear. LSP is the cornerstone of inheritance reuse. The base class can be reused only when the derived class can replace the base class and the function of the software unit is not affected. The derived class can also add new behaviors on the base class. Richter’s substitution principle is a complement to the open – close principle. Abstract is the key step to realize the open and close principle, and the inheritance relationship between base class and subclass is the concrete realization of abstraction, so the Richter substitution principle is the specification of the concrete steps to realize abstraction.
1.3.3 Dependence Inversion Principle
This principle is the basis of the open closed principle, the concrete content: programming for interfaces that rely on abstraction rather than on concrete.
1.3.4 Interface Segregation Principle
This principle means that it is better to use multiple isolated interfaces than a single one. It also has another meaning: reducing coupling between classes. Thus, in fact, design mode is a software design idea that starts from large-scale software architecture and is easy to upgrade and maintain. It emphasizes reducing dependence and coupling.
1.3.5 Demeter Principle, also known as Demeter Principle
The least known principle means that an entity should interact with other entities as little as possible, so that the functional modules of the system are relatively independent.
1.3.6 Composite Reuse Principle
The principle of composite reuse is to use composition/aggregation rather than inheritance whenever possible.
2. Detailed explanation of design mode
2.1 Creator Mode
2.1.1 Factory Mode
Factory Pattern is one of the most commonly used design patterns in Java. This type of design pattern is the creation pattern, which provides the best way to create objects.
In factory mode, we create objects without exposing the creation logic to the client, and by using a common interface to point to the newly created objects. Introduction intention: Define an interface to create an object and let its subclasses decide which factory class to instantiate. The factory pattern delays the creation process to subclasses.
Main solution: The main solution is interface selection.
When to use: We explicitly plan to create different instances under different conditions.
How to fix it: Subclasses implement the factory interface and return an abstract product.
Key code: The creation process is performed in its subclass.
Application example: 1. You need a car that can be picked up directly from the factory, regardless of how the car is made and the implementation of the car. Hibernate database change only need to change dialect and driver can be.
Advantages: 1. A caller who wants to create an object needs only to know its name. 2, high scalability, if you want to add a product, just extend a factory class can. 3, shield the concrete implementation of the product, the caller only cares about the interface of the product.
Disadvantages: Every time a product is added, a concrete class and object implementation factory need to be added, which doubles the number of classes in the system, increasing the complexity of the system to a certain extent, but also increasing the dependence of concrete classes in the system. This is not a good thing.
Usage scenarios: 1. Log logger: Records may be recorded to the local hard disk, system events, remote servers, and so on. Users can choose where to record logs. 2. Database access, when the user does not know which kind of database is used in the final system, and the database may change. 3, design a connection server framework, need three protocols, “POP3”, “IMAP”, “HTTP”, can take these three as a product class, common implementation of an interface.
Note: As a class creation pattern, the factory method pattern can be used anywhere complex objects need to be generated. It is important to note that complex objects are suitable for factory patterns, while simple objects, especially those that can be created by simply using New, do not need factory patterns. If you use the factory pattern, you need to introduce a factory class, which adds complexity to the system.
We will create a Shape interface and an entity class that implements the Shape interface. The next step is to define the factory class ShapeFactory.
FactoryPatternDemo, our demo class usesShapeFactoryIn order to getShapeObject. It will be toShapeFactoryConvey information (CIRCLE / RECTANGLE / SQUARE) to get the type of the object it needs.
//1. Create an interface
public interface Shape {
void draw(a);
}
//2. Create an entity class that implements the interface
public class Rectangle implements Shape{
@Override
public void draw(a) {
System.out.println("Inside Rectangle::draw() method."); }}public class Square implements Shape{
@Override
public void draw(a) {
System.out.println("Inside Square::draw() method."); }}public class Circle implements Shape{
@Override
public void draw(a) {
System.out.println("Inside Circle::draw() method."); }}//3. Create a factory class that generates objects of the entity class based on the given information.
public class ShapeFactory {
public Shape getShape(String shapeType) {
if (shapeType.equalsIgnoreCase("rectangle")) {
return new Rectangle();
}else if (shapeType.equalsIgnoreCase("square")) {
return new Square();
}else if (shapeType.equalsIgnoreCase("circle")) {
return new Circle();
}
return null; }}//4. Use the factory class to get the object of the entity class by passing the type information.
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory sf = new ShapeFactory();
sf.getShape("rectangle").draw();
sf.getShape("square").draw();
sf.getShape("circle").draw(); }}Copy the code
2.1.2 Abstract factory pattern
The Abstract Factory Pattern creates other factories around a gigafactory. The gigafactory is also known as the factory of other factories. This type of design pattern is the creation pattern, which provides the best way to create objects. In the abstract Factory pattern, an interface is a factory responsible for creating a related object, without explicitly specifying their classes. Each generated factory can provide objects according to the factory pattern.introduceIntent: Provide an interface for creating a series of related or interdependent objects without specifying their concrete classes. Main solution: The main solution is interface selection. When to use: The products of the system have more than one product family, and the system only consumes the products of one of these family. How to solve it: Define multiple products within a product family. Key code: the aggregation of multiple similar products in a factory. Application example: work, in order to attend some parties, there must be two or more sets of clothes, such as a business attire (complete, a series of specific products), fashionable outfit (complete, a series of specific products), even for a family, there may be business women’s clothing, men’s clothing, fashion women’s clothing, fashion men’s wear, these are complete, namely a series of specific products. Suppose a situation (does not exist in reality, otherwise, can not enter the communist, but beneficial to explain the abstract factory pattern), in your home, a wardrobe (factory) only one such clothes (complete, a series of specific products), every time with this set of clothes is natural to take out from the chest. Using OO thoughts to understand, all chest (factory) is chest (abstract factory) one of a class, and each set of clothes, including specific jacket (a specific products), pants (a specific products), these specific coat also is actually coat (abstract), specific pants also are pants (another abstract products). Advantages: When multiple objects in a product family are designed to work together, it ensures that the client always uses only objects in the same product family. Disadvantages: Product family extension is very difficult. To add a product in a series, you need to add code in both the abstract Creator and the concrete one. Use scenario: 1, QQ change skin, a set of change together. 2. Generate programs for different operating systems. Note: Product family is difficult to expand, product level is easy to expand.implementationWe will create Shape and Color interfaces and entity classes that implement them. The next step is to create the AbstractFactory class AbstractFactory. Next, we define factory classes ShapeFactory and ColorFactory, both of which extend AbstractFactory. Then create a FactoryProducer/generator class FactoryProducer. AbstractFactoryPatternDemo, our demo classes use FactoryProducer to obtain AbstractFactory object. It will pass the Shape information Shape (CIRCLE/RECTANGLE/SQUARE) to AbstractFactory to get the type of the object it needs. It also passes the Color information Color (RED/GREEN/BLUE) to AbstractFactory to get the type of object it needs.
1. Create an interface for the shape
public interface Shape {
void draw(a);
}
//2. Create an implementation class for the interface
public class Rectangle implements Shape {
@Override
public void draw(a) {
System.out.println("Inside Rectangle::draw() method."); }}//3. Create an interface for colors
public class Square implements Shape {
@Override
public void draw(a) {
System.out.println("Inside Square::draw() method."); }}//4. Create an entity class that implements the interface
public class Circle implements Shape {
@Override
public void draw(a) {
System.out.println("Inside Circle::draw() method."); }}public interface Color {
void fill(a);
}
public class Red implements Color {
@Override
public void fill(a) {
System.out.println("Inside Red::fill() method."); }}public class Green implements Color {
@Override
public void fill(a) {
System.out.println("Inside Green::fill() method."); }}public class Blue implements Color {
@Override
public void fill(a) {
System.out.println("Inside Blue::fill() method."); }}//5. Create abstract classes for Color and Shape objects to get factories.
public abstract class AbstractFactory {
public abstract Color getColor(String color);
public abstract Shape getShape(String shape) ;
}
//6. Create a factory class that extends AbstractFactory to generate objects of the entity class based on the given information.
public class ShapeFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
if(shapeType == null) {return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")) {return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")) {return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")) {return new Square();
}
return null;
}
@Override
public Color getColor(String color) {
return null; }}public class ColorFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
return null;
}
@Override
Color getColor(String color) {
if(color == null) {return null;
}
if(color.equalsIgnoreCase("RED")) {return new Red();
} else if(color.equalsIgnoreCase("GREEN")) {return new Green();
} else if(color.equalsIgnoreCase("BLUE")) {return new Blue();
}
return null; }}//7. Create a factory creator/generator class to retrieve factories by passing shape or color information.
public class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")) {return new ShapeFactory();
} else if(choice.equalsIgnoreCase("COLOR")) {return new ColorFactory();
}
return null; }}//8. Use FactoryProducer to get AbstractFactory, passing type information to get objects of the entity class.
public class AbstractFactoryPatternDemo {
public static void main(String[] args) {
// Get the shape factory
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
// Get an object of the shape Circle
Shape shape1 = shapeFactory.getShape("CIRCLE");
// Call Circle's draw method
shape1.draw();
// Get an object with a Rectangle shape
Shape shape2 = shapeFactory.getShape("RECTANGLE");
// Call the Rectangle draw method
shape2.draw();
// Get the object with the shape Square
Shape shape3 = shapeFactory.getShape("SQUARE");
// Call Square's draw method
shape3.draw();
// Get the color factory
AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
// Get the object with the color Red
Color color1 = colorFactory.getColor("RED");
// Call Red's fill method
color1.fill();
// Get the object with the color Green
Color color2 = colorFactory.getColor("Green");
// Call Green's fill method
color2.fill();
// Get the object with the color Blue
Color color3 = colorFactory.getColor("BLUE");
// Call Blue's fill methodcolor3.fill(); }}Copy the code
2.1.3 Singleton mode
The Singleton Pattern is one of the simplest design patterns in Java. This type of design pattern is the creation pattern, which provides the best way to create objects.
This pattern involves a single class that is responsible for creating its own objects while ensuring that only a single object is created. This class provides a way to access its unique objects directly, without instantiating the objects of the class.
Note:
1. A singleton class can have only one instance. 2. A singleton class must create its own unique instance. 3. The singleton class must provide this instance to all other objects.