如何实现带工厂创建器的工厂初始化器?优化多参数实例化
嗨,我来帮你搞定这两个问题——先聊聊带工厂创建器的工厂初始化器怎么实现,再给你拆解多参数实例化的优化思路,结合你提供的代码来具体说明~
简单来说,带工厂创建器的工厂模式就是「工厂的工厂」:我们先定义抽象的工厂接口,再实现多个具体工厂(每个工厂负责创建一类对象),最后用一个「工厂创建器」来根据需求返回对应的具体工厂,再由这些工厂去创建业务对象。这样能把对象创建的逻辑进一步解耦,尤其是当你有多个类似的类需要创建时,扩展性会更强。
结合你的MyClass,咱们来写个具体实现:
第一步:定义抽象工厂接口
先给工厂定一个统一的创建标准:
public interface IObjectFactory { object Create(object initParams); }
第二步:实现具体工厂(针对MyClass)
这个工厂专门负责创建和初始化MyClass:
public class MyClassFactory : IObjectFactory { public object Create(object initParams) { if (initParams is MyClassInitParams param) { MyClass instance = new MyClass(); if (instance != null && instance.Initialize(param)) { return instance; } } return null; } }
第三步:实现工厂创建器
这个类负责根据你传入的标识(比如类型名、枚举)返回对应的具体工厂:
public static class FactoryCreator { public static IObjectFactory GetFactory(string factoryType) { switch (factoryType) { case "MyClass": return new MyClassFactory(); // 以后新增其他类的工厂,直接在这里加case就行 default: throw new System.ArgumentException("Unsupported factory type"); } } }
第四步:改造你的MyClass适配新结构
把原来的多参数Initialize改成接收参数对象的形式(后面会详细说这个优化):
using UnityEngine; public class MyClass { float myFloat; int myInt; object[] myObjects; public bool Initialize(MyClassInitParams param) { myFloat = param.MyFloat; myInt = param.MyInt; myObjects = param.MyObjects; return true; } } // 定义参数对象,后面会用到 public class MyClassInitParams { public float MyFloat { get; set; } public int MyInt { get; set; } public object[] MyObjects { get; set; } }
调用示例
现在你可以通过工厂创建器拿到工厂,再创建对象:
// 1. 获取对应工厂 var factory = FactoryCreator.GetFactory("MyClass"); // 2. 准备初始化参数 var paramsObj = new MyClassInitParams { MyFloat = 3.14f, MyInt = 100, MyObjects = new object[] { "a", 1, true } }; // 3. 创建实例 MyClass myInstance = factory.Create(paramsObj) as MyClass;
这样一来,以后你新增其他需要工厂创建的类,只需要新增对应的工厂类和参数类,然后在FactoryCreator里加个case就行,完全符合开闭原则~
你提到要传10个参数的情况确实很头疼,这里给你几个实用的优化思路,按场景选就行:
1. 最常用:参数对象(Parameter Object)模式
这是解决多参数最直接的方法——把所有初始化参数封装成一个独立的类,这样不管多少个参数,只需要传一个对象就行,而且后续修改参数也不用改Create和Initialize的方法签名。
比如刚才上面用到的MyClassInitParams就是这个思路,改造后你的Create方法会变成这样:
public static MyClass Create(MyClassInitParams param) { MyClass instance = new MyClass(); if (instance != null && instance.Initialize(param)) { return instance; } return null; }
调用的时候只需要创建并赋值参数对象,可读性和维护性都大大提升。
2. 适合有默认值的场景:可选参数+默认值
如果你的部分参数有合理的默认值,可以给方法参数设置默认值,这样调用的时候只需要传必要的参数:
public static MyClass Create( float in_somefloat = 0f, int in_someInt = 0, object[] someObject = null) { MyClass instance = new MyClass(); if (instance != null && instance.Initialize(in_somefloat, in_someInt, someObject ?? new object[0])) { return instance; } return null; } // 调用示例:只传需要的参数 var instance1 = MyClass.Create(in_somefloat: 5.2f); var instance2 = MyClass.Create(in_someInt: 200, someObject: new object[] { "test" });
不过这个方案适合参数不多且默认值明确的情况,参数太多的话还是参数对象更清晰。
3. 适合复杂配置场景:构建者(Builder)模式
如果你的参数不仅多,而且很多是可选的,或者需要分步配置,构建者模式会非常合适。咱们给MyClass写个构建者:
public class MyClassBuilder { private float _myFloat = 0f; private int _myInt = 0; private object[] _myObjects = new object[0]; public MyClassBuilder SetFloat(float value) { _myFloat = value; return this; // 链式调用 } public MyClassBuilder SetInt(int value) { _myInt = value; return this; } public MyClassBuilder SetObjects(object[] value) { _myObjects = value ?? new object[0]; return this; } public MyClass Build() { MyClass instance = new MyClass(); instance.Initialize(_myFloat, _myInt, _myObjects); return instance; } } // 调用示例:链式设置参数,清晰直观 var myInstance = new MyClassBuilder() .SetFloat(3.14f) .SetInt(100) .SetObjects(new object[] { "a", 1 }) .Build();
这种方式的好处是可以灵活组合参数,而且代码可读性极高,尤其适合参数有多种组合的场景。
4. 适合依赖服务的场景:依赖注入(DI)
如果你的参数里有很多是依赖的服务(比如其他Manager、工具类),可以用Unity的依赖注入(或者第三方容器比如Zenject)来自动注入,不用手动传参。比如:
// 假设MyClass依赖一个IMyService public class MyClass { private IMyService _myService; float myFloat; int myInt; // 构造函数注入 public MyClass(IMyService myService) { _myService = myService; } public bool Initialize(float in_somefloat, int in_someInt) { myFloat = in_somefloat; myInt = in_someInt; return true; } }
然后在Unity里配置DI容器,创建实例时容器会自动注入IMyService的实现,你只需要传必要的业务参数就行。
内容的提问来源于stack exchange,提问作者user9673893

