Factory pattern
工廠模式(Factory pattern
):讓一個特別的物件(工廠Factory
)去建立其他物件(產品Product
)。它封裝了生成其他物件(產品Product
)的邏輯,最直接可見的好處是整理了你的程式碼。工廠物件可以有多種子類(subclass),用來產生多種不同的產品。
優點
- 使用工廠模式的好處是當你增加產品時,你不需要修改先前的程式碼就可以增加產品
缺點
- 增加程式碼的複雜度
建立一個IProduct介面,訂立產品必須要有的規則
- 每個產品一定要有自己的名字(
ProductName
) - 每個產品有初始化自己的方式(
Initialize()
) - 產品種類比較不會有共用的邏輯,因此將其設計為介面
1
2
3
4
5public interface IProduct
{
public string ProductName { get; set; }
public void Initialize();
}
以下建立一個抽象工廠,抽象工廠用來規定工廠必須要有的動作
- 每個工廠必須要能在對應的位置(
Vector3 position
)上生產產品(GetProduct()
)1
2
3
4
5
6public abstract class Factory : MonoBehaviour
{
public abstract IProduct GetProduct(Vector3 position);
// shared method with all factories
…
}
建立一個產品A
- 它含有一個
ParticleSystem
,並在初始化方法(Initialize)中會播放此ParticleSystem
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class ProductA : MonoBehaviour, IProduct
{
[private string productName = "ProductA"; ]
public string ProductName { get => productName; set => productName = value ; }
private ParticleSystem particleSystem;
public void Initialize()
{
// any unique logic to this product
gameObject.name = productName;
particleSystem = GetComponentInChildren<ParticleSystem>();
particleSystem?.Stop();
particleSystem?.Play();
}
}
建立一個工廠A
- 它含有一個產品A的依賴,在
GetProduct()
方法中建立產品A實體之後,會呼叫產品A實體上的Initialize()方法用來初始化該實體。1
2
3
4
5
6
7
8
9
10
11
12
13public class ConcreteFactoryA : Factory
{
[private ProductA productPrefab; ]
public override IProduct GetProduct(Vector3 position)
{
// 使用Prefab在指定的position上建立一個instance
GameObject instance = Instantiate(productPrefab.gameObject, position, Quaternion.identity);
ProductA newProduct = instance.GetComponent<ProductA>();
// 初始化產品A
newProduct.Initialize();
return newProduct;
}
}
建立一個產品B
- 它含有一個
AudioSource
,在初始化方法(Initialize)中會播放此AudioSource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class ProductB : MonoBehaviour, IProduct
{
[private string productName = "ProductB"; ]
public string ProductName { get => productName; set => productName = value; }
private AudioSource audioSource;
public void Initialize()
{
// do some logic here
audioSource = GetComponent<AudioSource>();
audioSource?.Stop();
audioSource?.Play();
}
}
建立一個工廠B
- 工廠B與工廠A類似,不過依賴換為產品B
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public class ConcreteFactoryB : Factory
{
// used to create a Prefab
[private ProductB productPrefab; ]
public override IProduct GetProduct(Vector3 position)
{
// create a Prefab instance and get the product component
GameObject instance = Instantiate(productPrefab.gameObject, position, Quaternion.identity);
ProductB newProduct = instance.GetComponent<ProductB>();
// each product contains its own logic
newProduct.Initialize();
// add any unique behavior to this factory
instance.name = newProduct.ProductName;
Debug.Log(GetLog(newProduct));
return newProduct;
}
}
建立一個使用工廠的類
ClickToCreate
這個類使用了工廠A與工廠B,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32public class ClickToCreate : MonoBehaviour
{
[private LayerMask layerToClick; ]
[private Vector3 offset; ]
[ ] Factory[] factories;
private Factory factory;
private void Update()
{
GetProductAtClick();
}
private void GetProductAtClick()
{
// check click with raycast
if (Input.GetMouseButtonDown(0))
{
// choose a random factory
factory = factories[Random.Range(0, factories.Length)];
// instantiate product at raycast intersection
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo, Mathf.Infinity, layerToClick) && factory != null)
{
factory.GetProduct(hitInfo.point + offset);
}
}
}
}