Introduction to Design Patterns

For experienced developers, learning design patterns helps us find the best solutions to the problems we face during software development. Software has always been used to solve complex problems in real life. The Design pattern is like a set of basic martial arts mind methods. Each pattern represents the best practice of a class of problems and can be combined according to the actual situation. In this series of articles, I will take you through design patterns from the ground up, and then examine the implementation of each of the 23 design patterns in Java. Readers are required to have basic Java programming concepts.

At the end of the article there is a welfare broadcast, thank you for reading.

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

Design patterns can speed up the development process by providing tested and proven development examples

Reusing design patterns helps prevent subtle problems that can cause major problems, while also improving code readability for programmers and architects familiar with the patterns

What is GOF(Gang of Four)

In 1994, Four authors, Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, published a book called Design Patterns – Elements of Reusable Object-oriented Software (DESIGN Patterns – Reusable Object-oriented Software Elements) is the first book to introduce the concept of design patterns in Software development.

The authors are collectively known as GOF (Gang of Four). The design patterns they propose are based on the following object-oriented design principles.

  • Program interfaces rather than implementations.
  • Prefer object composition to inheritance.

use

The primary use of design patterns is twofold. One is to provide a standard terminology system that is specific to a particular scenario. For example, the singleton design pattern means using a single object, so that all developers familiar with the singleton design pattern can use a single object and tell each other that the program is using the singleton pattern. Second, they provide best practices. Design patterns have been developed over a long period of time, and they provide the best solutions to common problems faced in software development. Learning these patterns helps inexperienced developers learn software design in an easy and quick way

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. There is another class of design patterns:

J2EE design pattern

. These design patterns can be classified into three levels from easy to difficult: Beginner, difficult-Intermediate & difficult-Expert. In the following articles, I will introduce different types of design patterns from easy to difficult.

The following picture gives an overview of the relationship between design patterns:

Six principles of design patterns

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.

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.

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.

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.

5. Demeter Principle, also known as the Least Known 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.

Composite Reuse Principle

The principle of composite reuse is to use composition/aggregation rather than inheritance whenever possible.

Thinking about design patterns

Before learning and understanding design patterns, you should familiarize yourself with some programming/software design principles. All design should be as simple as possible, starting with the simplest thing and gradually extending, this may be the principle of work learning.

They should only be introduced (design patterns) when there is a real need for extensibility, complexity and patterning. Once you are familiar with the concepts of these design patterns, you can choose the most appropriate pattern to elegantly achieve the engineering goals based on the actual engineering situation.

The factory pattern

Also known as Virtual Constructors, the 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

intentions

Define the interface to create an object, but let subclasses decide which class to instantiate. The Factory method allows classes to defer instantiation to subclasses

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.

explain

Real world examples

A blacksmith makes weapons. Elves need elven weapons. Orcs need orc weapons. Assemble the right type of blacksmith, depending on the customers at hand

In a nutshell

It provides a way to delegate instantiation logic to subclasses

Wikipedia says

In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects By calling a factory method — either specified in an interface and implemented by child classes, Or implemented in a base class and optionally overridden by derived classes — rather than by calling a In class-based programming, the Factory method pattern is a creation pattern that uses the Factory method to handle the creation of an object without specifying the exact class of the object to be created This is done by calling the Factory method (specified in the interface and implemented by subclasses, or implemented in the base class and optionally overridden by derived classes), rather than by calling the constructor.

Program code example

In the real world example of a blacksmith making a weapon, we summon a blacksmith for the type of weapon needed. The program class diagram is as follows:

Blacksmith interface implementation class diagram. PNG

First we have a blacksmith interface (which defines a method for making weapons) and some elf blacksmith and Orc blacksmith implementation classes:

public interface Blacksmith {
 Weapon manufactureWeapon(WeaponType weaponType);
}
public class ElfBlacksmith implements Blacksmith {
 public Weapon manufactureWeapon(WeaponType weaponType) {
 return new ElfWeapon(weaponType);
 }
}
public class OrcBlacksmith implements Blacksmith {
 public Weapon manufactureWeapon(WeaponType weaponType) {
 returnnew OrcWeapon(weaponType); }} Copy the codeCopy the code

Second, we have a weapon interface (which defines a method to get the weapon type) and some elf and Orc weapon implementation classes:

/**
* Weapon interface.
*/
public interface Weapon {
 WeaponType getWeaponType();
}
/**
* ElfWeapon.
*/
public class ElfWeapon implements Weapon {
 private WeaponType weaponType;
 public ElfWeapon(WeaponType weaponType) {
 this.weaponType = weaponType;
 }
 @Override
 public String toString() {
 return "Elven " + weaponType;
 }
 @Override
 public WeaponType getWeaponType() {
 return weaponType;
 }
}
/**
* OrcWeapon.
*/
public class OrcWeapon implements Weapon {
 private WeaponType weaponType;
 public OrcWeapon(WeaponType weaponType) {
 this.weaponType = weaponType;
 }
 @Override
 public String toString() {
 return "Orcish " + weaponType;
 }
 @Override
 public WeaponType getWeaponType() {
 returnweaponType; }} Copy the codeCopy the code

Finally, as customers arrive, the right type of blacksmith is summoned and asked to make weapons

public class App {
 private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
 private final Blacksmith blacksmith;
 
 /**
 * Creates an instance of <code>App</code> which will use <code>blacksmith</code> to manufacture 
 * the weapons for war.
 * <code>App</code> is unaware which concrete implementation of {@link Blacksmith} it is using.
 * The decision of which blacksmith implementation to use may depend on configuration, or
 * the type of rival in war.
 * @param blacksmith a non-null implementation of blacksmith
 */
 public App(Blacksmith blacksmith) {
 this.blacksmith = blacksmith;
 }
 
 /**
 * Program entry point
 * 
 * @param args command line args
 */
 public static void main(String[] args) {
 // Lets go to war with Orc weapons
 App app = new App(new OrcBlacksmith());
 app.manufactureWeapons();
 
 // Lets go to war with Elf weapons
 app = new App(new ElfBlacksmith());
 app.manufactureWeapons();
 }
 
 private void manufactureWeapons() { Weapon weapon; weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR); LOGGER.info(weapon.toString()); weapon = blacksmith.manufactureWeapon(WeaponType.AXE); LOGGER.info(weapon.toString()); }} Copy the codeCopy the code

Results of running the App:

App running result output. PNG

Applicable scenario

The factory mode should be used when there are three situations:

  1. A class that cannot predict the object it must create
  2. A class wants its subclasses to specify the object it creates
  3. The class delegates responsibility to one of several helper subclasses, and which helper subclass you wish to localize is the delegate’s responsibility

A real world example in Java

  • java.util.Calendar
  • java.util.ResourceBundle
  • java.text.NumberFormat
  • java.nio.charset.Charset
  • java.net.URLStreamHandlerFactory
  • java.util.EnumSet
  • javax.xml.bind.JAXBContext

The advantages and disadvantages

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.
  3. Masking the concrete implementation of the product, the caller only cares about the interface of the product

Disadvantages:

Each time a product is added, it is necessary to add a concrete implementation class and modify the object implementation factory, doubling the number of classes in the system, increasing the complexity of the system to a certain extent, but also increasing the dependence of the system concrete classes. That’s not a good thing, right

The last

The factory pattern, as a creation class pattern, can be used wherever complex objects need to be generated, such as designing a framework to connect to a server that requires three protocols, “POP3”, “IMAP”, and “HTTP”. These three can be used as product classes to implement a communication interface.

For simple objects, especially objects that can be created only through new, there is no need to use the factory pattern, because using the factory pattern will necessarily introduce a factory class, which will increase the complexity of the system.

Then we will continue to introduce the abstract factory model based on the factory model. The difficulty system is intermediate

Recommend a learning circle: 697-57-9751, which will share some veteran architects recorded video: Spring, MyBatis, Netty source code analysis, high concurrency, high performance, distributed, microservice architecture principle, JVM performance optimization these become the architect’s necessary knowledge system. You can also receive free learning resources, which have benefited a lot at present: