23 design patterns
Design pattern (design pattern) is an important technology in software engineering. It is used to solve specific problems in a specific context. A universal solution is adopted. Design patterns can help software engineers improve code reusability, maintainability, and scalability.
23 common design patterns can be divided into the following categories:
- Creational patterns: These patterns are used to create objects, including factory method pattern, abstract factory pattern, singleton pattern, builder pattern and prototype pattern.
- Structural patterns: These patterns are used to organize the structure of classes and objects, including adapter pattern, bridge pattern, composition pattern, decorator pattern, appearance pattern, Flyweight mode and proxy mode.
- Behavioral patterns: These patterns are used to define the interaction and responsibility distribution between classes or objects, including chain of responsibility pattern, command pattern, interpreter pattern, Iterator pattern, Mediator pattern, Memo pattern, Observer pattern, State pattern, Strategy pattern, Template method pattern and Visitor pattern.
Six principles of design patterns
- Single Responsibility Principle ( Single Responsibility Principle): A class should have only one reason for its change.
- Open and closed principle ( Liskov Substitution Principle): Software entities (classes, modules, functions, etc.) should be extensible but not modifiable.
- Richter Substitution Principle (Liskov Substitution Principle): Subclasses can replace parent classes.
- Dependency Inversion Principle ( Dependence Inversion Principle): High-level modules should not depend on low-level modules, but should rely on abstractions.
- Interface isolation principle ( Interface Segregation Principle): A client should not rely on interfaces it does not need.
- Demeter’s Law (Law of Demeter): An object should know as little as possible about other objects.
1. Factory Pattern: Create a factory class to create instances of other classes.
Factory pattern is a creational design pattern that provides a way to create objects without directly instantiating classes. The factory pattern encapsulates the process of creating objects in a separate factory class. The client can create the required objects through the factory class without caring about the specific implementation details of the object.
Factory pattern can be divided into simple factory pattern, factory method pattern and abstract factory pattern.
Simple factory pattern: Provide a factory class that can create different product objects based on the parameters passed in.
Factory method pattern: Define a factory interface and let different subclasses implement this interface. The client can create different product objects by calling the factory interface.
Abstract factory pattern: Provide an abstract factory interface and let different subclasses implement this interface. The client can create a series of related product objects by calling the abstract factory interface .
Factory mode The advantages and disadvantages are as follows:
Advantages:
- <span style="font-family: "Microsoft YaHei"nbsp;
Visitor
class and an Element
class. The Element
class represents the element in the data structure to be accessed. It contains a method that accepts Visitor
access. The Visitor
class is an abstract class that defines methods for accessing the Element
class. Specific Visitor
subclasses implement these methods to perform specific operations on the Element
class.
The advantages and disadvantages of visitor mode are as follows:
advantage:
- Extensibility: System functionality can be extended by adding new visitor classes without modifying the existing class structure.
- Separate operations and data structures: The visitor pattern separates the operations on the data structure from the data structure itself, allowing new operations to be added without changing the data structure.
- Flexibility: The visitor pattern allows many different operations on the data structure without modifying the data structure itself.
- Easy to understand and maintain: The visitor pattern has a clear structure and is easy to understand and maintain.
shortcoming:
- Increased complexity: The visitor pattern increases the complexity of the system and requires more classes and objects to implement.
- Performance issues: In some cases, the visitor pattern may cause performance issues because of the need to traverse the data structure to perform operations.
- Difficult to test: Testing the visitor pattern can be difficult because of the need to test the interaction between multiple visitor classes and element classes.
- Difficult to understand: In some cases, the visitor pattern may make the code difficult to understand, especially when there are a large number of visitor classes and element classes in the system.
The following are some common visitor pattern application scenarios:
- The operations of data structures need to be customized according to different situations.
- The data structure needs to support multiple different operations at the same time, but there are logical differences between these operations.
- Many different operations need to be performed on the data structure, but these operations need to be performed at different times or places.
- Operations on data structures need to be performed in different contexts, such as in different applications or modules.
- Requires complex operations on data structures, such as recursive operations or multi-step operations.
In general, the visitor pattern is suitable for scenarios that require many different operations on data structures, and these operations need to be performed at different times, places, or contexts. By using the visitor pattern, you can separate the operations on the data structure from the data structure itself, improving the scalability and maintainability of the code.
The following is an example of using C# to implement the visitor pattern:
View code
using System;
public interface IElement
{
void Accept(IVisitor visitor);
}
public interface IVisitor
{
void Visit(IElement element);
}
public class ConcreteElement1 : IElement
{
public void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
public class ConcreteElement2 : IElement
{
public void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
public class ConcreteVisitor1 : IVisitor
{
public void Visit(IElement element)
{
Console.WriteLine("Visiting concreteElement1");
}
}
public class ConcreteVisitor2 : IVisitor
{
public void Visit(IElement element)
{
Console.WriteLine("Visiting concreteElement2");
}
}
public class Program
{
public static void Main()
{
var element1 = new ConcreteElement1();
var element2 = new ConcreteElement2();
var visitor1 = new ConcreteVisitor1();
var visitor2 = new ConcreteVisitor2();
element1.Accept(visitor1);
element2.Accept(visitor1);
element1.Accept(visitor2);
element2.Accept(visitor2);
}
}
In the above example, IElement
is an interface that represents an element, and it contains a method that accepts visitors Accept
. IVisitor
is an interface representing a visitor, which contains a method Visit
for accessing elements.
ConcreteElement1
and ConcreteElement2
are concrete implementations of IElement
and they represent different elements. ConcreteVisitor1
and ConcreteVisitor2
are specific implementations of IVisitor
, and they represent different visitors. In the Main
method, we create two elements and two visitors, and use the Accept
method to pass the elements to the visitors for access. Since visitors are implemented polymorphically, different visitors can be used to perform different operations on elements.
These design patterns are very common in software development and can help developers solve many common problems and improve the reusability and maintainability of code. and scalability.
�Design patterns are very common in software development and can help developers solve many common problems and improve code reusability, maintainability and scalability.