工厂方法

16 篇文章 0 订阅
1 篇文章 0 订阅

工厂方法

简单工厂的优缺点

优点:

​ 将子类的创建与具体的应用场景解藕,使得修改和新增产品类型时只需要维护工厂,而不用考虑实际应用场景

缺点:

​ 1.在新增和修改产品创建时,依然要修改工厂,违反了开闭原则,随着类型的增多将不断增加该类的逻辑

​ 2.工厂类集中了所有产品的创建逻辑,一旦发生问题将影响整个系统

工厂方法

​ 工厂方法通过对工厂进行一次抽象,将具体产品的创建交给具体工厂去完成,从而避免了对核心工厂抽象的修改,并且分离了创建逻辑,使得各个产品能够独立完成创建。
在这里插入图片描述
​ 以手机工厂举例,产品和工厂接口

namespace DesignModel.FactoryMethod
{
	public enum PhoneType
	{
		Inviled = -1,
		iPhoneXs = 1,
		VivoPhone = 2
	}
    public interface IProduct  
    {
        void Show();
        void Check();
        PhoneType GetPhoneType();
    }
    public interface IFactory 
	{
		IProduct CreateProduct();
	}
}

iphone和vivo手机产品

namespace DesignModel.FactoryMethod
{
	public class iPhoneXs : IProduct 
	{
		public PhoneType GetPhoneType()
		{
			return PhoneType.iPhoneXs;
		}
		public void Show()
		{
			Debug.Log("Show iPhone Xs");
		}

		public void Check()
		{
			Debug.Log("Check iPhone Xs");
		}
	}
	
	public class VivoPhone : IProduct 
	{
		public PhoneType GetPhoneType()
		{
			return PhoneType.VivoPhone;
		}
		public void Show()
		{
			Debug.Log("Show vivo Phone");
		}

		public void Check()
		{
			Debug.Log("Check vivo Phone");
		}
	}
}

对应的工厂

namespace DesignModel.FactoryMethod
{
	public class iPhoneFactory : IFactory 
	{
		public IProduct CreateProduct()
		{
			return new iPhoneXs();
		}
	}
	public class VivoFactory : IFactory 
	{
		public IProduct CreateProduct()
		{
			return new VivoPhone();
		}
	}
}

简单的客户端测试

public class FactoryMethodClient : MonoBehaviour 
{
	void Start () 
	{
		IProduct phone1 = new iPhoneFactory().CreateProduct();
		phone1.Show();

		IProduct phone2 = new VivoFactory().CreateProduct();
		phone2.Show();
	}
}
拓展

改进对象池,使得它使用工厂方法

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

namespace DesignModel.FactoryMethod
{
	public class PhonePoolManager
	{
		//单例
		private static PhonePoolManager instance = null;
		public static PhonePoolManager Instance
		{
			get
			{
				if (instance == null) instance = new PhonePoolManager();
				return instance;
			}
		}
		
		//对象池
		private Dictionary<PhoneType,List<IProduct>> pool;
		//私有化初始化,并填充对象池类型
		private PhonePoolManager()
		{
			pool = new Dictionary<PhoneType, List<IProduct>>();
			pool.Add(PhoneType.iPhoneXs, new List<IProduct>());
			pool.Add(PhoneType.VivoPhone, new List<IProduct>());
		}

		/// <summary>
		/// 获取Phone对象
		/// </summary>
		/// <param name="type">要获取的对象类型</param>
		public IProduct GetPhone(PhoneType type)
		{
			IProduct phone = null;
			if (pool[type].Count <= 0)
				phone = CreatePhone(type);
			else
			{
				phone = pool[type][0];
				pool[type].RemoveAt(0);
			}
			return phone;
		}

		private IProduct CreatePhone(PhoneType type)
		{
			switch(type)
			{
				case PhoneType.VivoPhone:
					return new VivoFactory().CreateProduct();
				case PhoneType.iPhoneXs:
					return new iPhoneFactory().CreateProduct();
				default:
					return null;
			}
		}


		/// <summary>
		/// 回收phone对象
		/// </summary>
		/// <param name="item">要回收的对象</param>
		public void RecoverPhone(IProduct item)
		{
			switch(item.GetPhoneType())
			{
				case PhoneType.VivoPhone:
					pool[PhoneType.VivoPhone].Add(item);
				break;
				case PhoneType.iPhoneXs:
					pool[PhoneType.iPhoneXs].Add(item);
				break;
			}
		}
	}
}
工厂方法的局限

可以看到在对象池中,具体的创建逻辑是这一部分

		private IProduct CreatePhone(PhoneType type)
		{
			switch(type)
			{
				case PhoneType.VivoPhone:
					return new VivoFactory().CreateProduct();
				case PhoneType.iPhoneXs:
					return new iPhoneFactory().CreateProduct();
				default:
					return null;
			}
		}

我们可以看到,虽然产品的创建和具体的产品分离,但我们依然需要知道对应工厂的类型,并且创建对应工厂的实例

总结工厂方法的局限如下:

1.每个产品都要有一个对应的工厂,类的数量和复杂性加倍了,会给程序带来额外开销

2.虽然工厂本身对修改封闭了,但对于使用工厂方法的类,例如上面的PhonePoolManager,一旦产品发生变化,依然要修改对应部分的代码CreatePhone

应用

在实际应用中,我们可以将工厂名配置在配置文件中,通过反射去获取类型,避免对代码的修改.

例如在我们的CreatePhone函数中,我们可以将PhoneType保存为类名字符串,从而通过工厂类名反射获取对应类型,创建对应产品。

用反射重写PhonePoolManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;

namespace DesignModel.FactoryMethod
{
	public class PhonePoolManager
	{
		private const string NAME_SPACE = "DesignModel.FactoryMethod";
		
		//单例
		private static PhonePoolManager instance = null;
		public static PhonePoolManager Instance
		{
			get
			{
				if (instance == null) instance = new PhonePoolManager();
				return instance;
			}
		}
		
		//对象池
		private Dictionary<string,List<IProduct>> pool;
		//私有化初始化,并填充对象池类型
		private PhonePoolManager()
		{
			pool = new Dictionary<string, List<IProduct>>();
		}

		/// <summary>
		/// 获取Phone对象
		/// </summary>
		/// <typeparam name="T">对象工厂类型</typeparam>
		public IProduct GetPhone<T>() where T : IFactory, new()
		{
			return GetPhone(new T().GetType().Name);
		}

		/// <summary>
		/// 获取Phone对象
		/// </summary>
		/// <param name="type">要获取的对象工厂类型</param>
		public IProduct GetPhone(string type)
		{
			IProduct phone = null;
			if (pool.ContainsKey(type) && pool[type].Count > 0)
			{
				phone = pool[type][0];
				pool[type].RemoveAt(0);
			}
			else
			{
				phone = CreatePhone(type);				
			}
			return phone;
		}

		private IProduct CreatePhone(string type)
		{
			string fullName = NAME_SPACE + "." + type;
			Assembly assembly = Assembly.GetExecutingAssembly();
			IFactory factory = (IFactory)assembly.CreateInstance(fullName);
			if (factory != null)
				return factory.CreateProduct();

			return null;
		}


		/// <summary>
		/// 回收phone对象
		/// </summary>
		/// <param name="item">要回收的对象</param>
		public void RecoverPhone(IProduct item)
		{
			if (!pool.ContainsKey(item.GetType().Name))
			{
				pool.Add(item.GetType().Name, new List<IProduct>());
			}

			if (!pool[item.GetType().Name].Contains(item))
				pool[item.GetType().Name].Add(item);
		}
	}
}

简单的测试

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace DesignModel.FactoryMethod
{
	public class FactoryMethodClient : MonoBehaviour 
	{
		void Start () 
		{
			IProduct phone3 = PhonePoolManager.Instance.GetPhone<iPhoneFactory>();
			phone3.Show();
			PhonePoolManager.Instance.RecoverPhone(phone3);

			IProduct phone4 = PhonePoolManager.Instance.GetPhone("VivoFactory");
			phone4.Show();
			PhonePoolManager.Instance.RecoverPhone(phone4);

			IProduct phone5 = PhonePoolManager.Instance.GetPhone<iPhoneFactory>();
			phone5.Show();
			PhonePoolManager.Instance.RecoverPhone(phone5);
		}
	}
}

测试结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值