Unity commonly used design patterns

One, singleton mode

In our entire game life cycle, there are many objects from beginning to end and only one. This unique instance only needs to be generated once, and does not need to be destroyed until the end of the game.
The singleton pattern is generally applied to manager classes, or some objects that need to be persisted.

Advantages: It is very convenient to write and easy to call.
Disadvantages: easy to form dependence, neglecting collaboration with other design patterns.

Unity's two singleton modes

  • Inherit the singleton of MonoBehaviour
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
    
    
    public static GameManager _instance;
    void Awake()
    {
    
    
        _instance = this;
    }
}
  • Does not inherit the singleton of MonoBehaviour
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InstanceManager
{
    
    
    private static InstanceManager _instance;
    public static InstanceManager Instance
    {
    
    
        get
        {
    
    
            if (_instance == null)
            {
    
    
                _instance = new InstanceManager();
            }
            return _instance;
        }
    }
}

Second, the factory model

This type of design pattern is a creational pattern, which provides the best way to create objects.

In the factory model, we do not expose the creation logic to the client when we create an object, and we use a common interface to point to the newly created object.

Application examples: 1. You need a car, and you can pick up the goods directly from the factory, regardless of how the car is made and the specific implementation in the car.
2. Hibernate only needs to change the dialect and driver to change the database.

Advantages: 1. A caller wants to create an object, as long as he knows its name.
2. High scalability. If you want to add a product, you only need to extend a factory class.
3. Shield the specific implementation of the product, and 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, which increases the complexity of the system to a certain extent, and also increases the number of specific classes in the system. rely. This is not a good thing.

Take the production car as an example. There are three types of Geely, Hongqi, and Volkswagen. These three are all cars. Then we first write a car interface. Car can also use the base class. The performance is the same. The three types of people have Productionr methods.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface Car
{
    
    
    void Production();
}

public class VW :Car
{
    
    
    public void Production()
    {
    
    
        Debug.Log("生产一辆大众");
    }
}

public class GeelyAutomobile : Car
{
    
    
    public void Production()
    {
    
    
        Debug.Log("生产一辆吉利");
    }
}

public class RedFlagCar : Car
{
    
    
    public void Production()
    {
    
    
        Debug.Log("生产一辆红旗");
    }
}

The three car classes have been created. To start factory production, create a factory class Clientele, pass in the agreed string/Int/ type, and you can start production. Here we use a static production method to proceed. Production, so the simple factory model is also called the static production model.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Clientele
{
    
    

    public static Car Clienteles(string carname)
    {
    
    
        switch (carname)
        {
    
    
            case "VW":
                return new VW();

            case "GeelyAutomobile":
                return new GeelyAutomobile();

            case "RedFlagCar":
                return new RedFlagCar();

            default:
                break;
        }
        return null;
    }
}

Now we have to do a test, we are going to produce and process the car, we only need to pass in the type we want to produce, and then we can return to the instance you need

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Texter : MonoBehaviour {
    
    

    void Start()
    {
    
    
        VW vW = (VW) Clientele.Clienteles("VW");
        vW.Production();

        GeelyAutomobile geelyAutomobile = (GeelyAutomobile)Clientele.Clienteles("GeelyAutomobile");
        geelyAutomobile.Production();

        RedFlagCar redFlagCar = (RedFlagCar)Clientele.Clienteles("RedFlagCar");
        redFlagCar.Production();
    }
}

Throw the Test.cs script into the scene, run it and have a look
Insert picture description here

Observer mode

Corresponding to the event mechanism, by adding listeners to obtain state changes.

The main solution:

The observer pattern draws a clear boundary between the modules and improves the maintainability and reusability of the application (this sentence comes from Baidu Encyclopedia).
Explain the above sentence with my own understanding. Using the observer pattern can avoid direct calls between classes and reduce coupling, that is, class A needs to monitor class B, but it can run even if class B is not present.

When to use: When the state of an object (target object) changes, all dependent objects (observer objects) will be notified and broadcast notifications.

Applications:

1. During the auction, the auctioneer observes the highest bid and then informs other bidders to bid.
2. In Journey to the West, Wukong asked the Bodhisattva to surrender the Red Boy. The Bodhisattva sprinkled water on the ground and attracted an old turtle. This tortoise was the observer. He observed the action of the Bodhisattva sprinkling water.
3. The example encountered is communication between the lower layer and the upper layer. The framework is designed to maintain a one-way dependency, that is, the upper layer depends on the lower layer, the view layer obtains data from the business layer, and the business layer depends on the basic class library.
However, the lower layer also needs to obtain the state change of the upper layer. In order not to violate the principle of one-way dependence, the observer mode can be used to monitor the upper layer to obtain the state change.

advantage:

1. The observer and the observed are abstractly coupled.
2. Establish a trigger mechanism.

Disadvantages:

1. If an observed object has many direct and indirect observers, it will take a lot of time to notify all observers.
2. If there is a circular dependency between the observer and the observation target, the observation target will trigger a cyclic call between them, which may cause the system to crash.
3. The observer mode does not have a corresponding mechanism to let the observer know how the observed target has changed, but only knows that the observed target has changed.

Command mode

The command mode is a mode in which the state and behavior of the object are encapsulated and processed according to certain rules.

The main solution: you can separate the requester of the behavior from the implementer of the behavior. For example, if you need to start recording in the game, you need to record the input instructions. If the requester and implementer of the behavior are tightly coupled (execute by pressing the button) Not conducive to recording.

advantage:

1. Reduce the degree of system coupling.
2. New commands can be easily added to the system.
3. The first advantage of this mode is to reduce the degree of coupling, such as the example above. Secondly, because the requester is separated from the implementation, we can do many operations on the requested instructions, such as adding new instructions, modifying instructions, and so on.

Example: I actually encountered an example of communication between modules. For example, my game has a login module and a network module. When the login module receives the login information, it needs to send information to the server for verification through the network module. If you call it directly The XXX function of the network module. Assuming that this function has not been written or even written, the game cannot run and debug. At this time, you can write a module manager. If you need to call another module's function, you can send a message to the module. The manager sends the information, and if the module does not exist, it caches the information, and then sends it when it is available. This is static decoupling, that is, decoupling on compilation, and it can run even if another module is not yet available.

To supplement the two design patterns, you can take a look. If there are any problems or errors, everyone is welcome to raise them, thanks! ! !
Follow-up will add and write here today.
Thank you all for your support.

Guess you like

Origin blog.csdn.net/m0_47605113/article/details/111589335