On design pattern and its application in Unity: II. Factory pattern

What is the factory model

Factory Pattern is one of the most commonly used design patterns. This type of design pattern is a creation pattern, which provides the best way to create objects.
In factory mode, when creating objects, we do not expose the creation logic to the client, and point to the newly created objects by using a common interface.

Give me a link to specific concepts: Factory model concept

Specific scenario

For example, we now have a factory generated computer, including Dell, ASUS and Acer. Users need to buy computers and factories need to produce computers, but there are three kinds of computers that users buy. For example, if our users want Dell, they must give them a Dell computer. Then this situation can be solved with the factory model. The user gives the demand (the name of the computer to be produced), factory production (instantiate the specific computer), and the return value after production is returned to the caller (the computer is delivered to the user after production).

How to implement factory mode (C# Implementation)

Step 1

First, there should be a computer interface

public interface Computer {
   void Func();
}

Step 2

Then there is a specific computer to create an entity class that implements the interface.

public class Dell : Computer {
 
   public override void Func()
   {
    	
   }
   
}
public class ASUS: Computer {
 
   public override void Func()
   {
      
   }
   
}
public class Acer: Computer {
 
   public override void Func()
   {
      
   }
   
}

Step 3

Create a factory to generate objects of entity classes based on the given information.

public class Factory {
    
   //Use the getShape method to get an object of shape type
   public Computer GetComputer(string computerName)
   {
      	if(computerName == null)
      	{
        	result = null;
      	}
   	  	Computer result = null;
   	  	switch(computerName)
   	  	{
			case: "Dell":
				result = new Dell();
				break;
			case: "ASUS":
				result = new ASUS();
				break;
			case: "Acer":
				result = new Acer();
				break;
			default:
				result = null;
				break;
		}
      	return result;
   }
}

Step 4

Using this factory, the object of the entity class is obtained by passing type information.

public class FactoryPatternDemo
{
 
   public static void Main(String[] args) {
   
      Factory factory = new Factory();
 
      //Get the Dell object and call its Func method
      Computer dell = factory.GetComputer("Dell");
 
      //Call Dell's Func method
      dell.Func();
 
      //Get the object of ASUS and call its Func method
      Computer asus = factory.GetComputer("ASUS");
 
      //Call Func method of ASUS
      asus.Func();
 
      //Get the object of Acer and call its Func method
      Computer acer = factory.GetComputer("Acer");
 
      //Call the Func method of Acer
      acer.Func();
   }
}

Application in Unity (singleton mode + object pool + factory mode)

For the singleton mode, please refer to my previous article: On design pattern and its application in Unity: I. single case pattern
See my article on object pool: Unity shooting game method of firing bullets and tips to improve fluency

Specific scenario

For example, there is a shooting game. There are many guns: pistols, rifles, shotguns, sniper rifles, submachine guns, etc. each weapon has its own bullets.
When shooting, we can ask the factory to create bullets and return.

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

public class BulletFactory : Singleton<BulletFactory>, BaseFactory
{
    //Rifle bullet object pool
    private Stack<BulletController> m_rifleBulletPool = new Stack<BulletController>();
    //Sniper rifle bullet object pool
    private Stack<BulletController> m_sniperBulletPool = new Stack<BulletController>();
    //Pistol bullet object pool
    private Stack<BulletController> m_handGunBulletPool = new Stack<BulletController>();
    //Shotgun bullet object pool
    private Stack<BulletController> m_shotGunBulletPool = new Stack<BulletController>();
    //Submachine gun bullet object pool
    private Stack<BulletController> m_sMGBulletPool = new Stack<BulletController>();

    //Rifle bullet preform
    public BulletController AssaultRifleBulletPrefab;
    //Sniper rifle bullet preform
    public BulletController SniperBulletBulletPrefab;
    //Pistol bullet preform
    public BulletController HandGunBulletPrefab;
    //Shotgun bullet preform
    public BulletController ShotGunBulletPrefab;
    //Submachine gun bullet preform
    public BulletController SMGBulletPrefab;
    protected override void Awake()
    {
        base.Awake();
        DontDestroyOnLoad(this);
    }
    /// <summary>
    ///Called when a bullet is created
    /// </summary>
    ///< param name = "producename" > bullet Name: AssaultRifle, Sniper, Handgun, SMG, shotgun < / param >
    ///< returns > bullet < / returns >
    public Component Creat(string produceName)
    {
        BulletController res = null;
        switch (produceName)
        {
            case "AssaultRifle":
                if(m_rifleBulletPool.Count >= 1)
                {
                    res = m_rifleBulletPool.Pop();
                }
                else
                {
                    res = Instantiate(AssaultRifleBulletPrefab);
                }
                break;
            case "Sniper":
                if (m_sniperBulletPool.Count >= 1)
                {
                    res = m_sniperBulletPool.Pop();
                }
                else
                {
                    res = Instantiate(SniperBulletBulletPrefab);
                }
                break;
            case "Handgun":
                if (m_handGunBulletPool.Count >= 1)
                {
                    res = m_handGunBulletPool.Pop();
                }
                else
                {
                    res = Instantiate(HandGunBulletPrefab);
                }
                break;
            case "SMG":
                if (m_sMGBulletPool.Count >= 1)
                {
                    res = m_sMGBulletPool.Pop();
                }
                else
                {
                    res = Instantiate(SMGBulletPrefab);
                }
                break;
            case "ShotGun":
                if (m_shotGunBulletPool.Count >= 1)
                {
                    res = m_shotGunBulletPool.Pop();
                }
                else
                {
                    res = Instantiate(ShotGunBulletPrefab);
                }
                break;
            default:
                break;
        }
        res.gameObject.SetActive(true);
        return res.transform;
    }
    /// <summary>
    ///Called when a bullet is created
    /// </summary>
    ///< param name = "producename" > bullet Name: AssaultRifle, Sniper, Handgun, SMG, shotgun < / param >
    ///< param name = "position" > bullet position < / param >
    ///< param name = "rotation" > bullet rotation < / param >
    ///< returns > bullet < / returns >
    public Component Creat(string produceName, Vector3 position, Quaternion rotation)
    {
        Component go = Creat(produceName);
        go.transform.position = position;
        go.transform.rotation = rotation;
        return go;
    }
    /// <summary>
    ///Bullet rejoin object pool call
    /// </summary>
    ///< param name = "producename" > bullet Name: AssaultRifle, Sniper, Handgun, SMG, shotgun < / param >
    ///< param name = "go" > bullet < / param >
    public void RecoveryGameObjectToPool(string produceName, Component go)
    {
        switch (produceName)
        {
            case "AssaultRifle":
                m_rifleBulletPool.Push(go as BulletController);
                break;
            case "Sniper":
                m_sniperBulletPool.Push(go as BulletController);
                break;
            case "Handgun":
                m_handGunBulletPool.Push(go as BulletController);
                break;
            case "SMG":
                m_shotGunBulletPool.Push(go as BulletController);
                break;
            case "ShotGun":
                m_sMGBulletPool.Push(go as BulletController);
                break;
            default:
                break;
        }
        go.gameObject.SetActive(false);
    }
}

Call method

public void CreatBullet(string bulletName)
{
	Component bullet = BulletFactory.Ins.Creat(bulletName);
}

Upgrade of factory pattern -- Abstract Factory Pattern

In the next article, let's further optimize the factory pattern: abstract factory pattern

Keywords: Unity Design Pattern

Added by yhingsmile on Wed, 05 Jan 2022 13:06:22 +0200