Unity3d 在由代码创建的组件上设置必填字段的选项?

Unity3d 在由代码创建的组件上设置必填字段的选项?,unity3d,encapsulation,Unity3d,Encapsulation,当我创建一个像下面这样的游戏对象时,我希望我的组件具有/设置必填字段 GameObject go = new GameObject("MyGameObject"); MyComponent myComponent = go.addComponent(MyComponent); 因为我不能使用构造函数来设置私有字段,所以我需要为这些字段设置一个setter,或者使用一个公共Init函数来设置多个强制属性。但这允许在代码中的任何位置更改值,与重载构造函数不同的是,Init“需要”或“可以”在创建后

当我创建一个像下面这样的
游戏对象时,我希望我的组件具有/设置必填字段

GameObject go = new GameObject("MyGameObject");
MyComponent myComponent = go.addComponent(MyComponent);
因为我不能使用构造函数来设置私有字段,所以我需要为这些字段设置一个setter,或者使用一个公共
Init
函数来设置多个强制属性。但这允许在代码中的任何位置更改值,与重载构造函数不同的是,
Init
“需要”或“可以”在创建后调用来设置这些参数并不明显


那么,还有其他选项允许我在创建组件时设置必填字段并使用“适当”封装吗?

正如注释中所述,Unity为MonoBehavior初始化逻辑实现了两种主要方法:和

这两种初始化方法都有缺点:

  • 它们不能接受任何参数
  • 你不确定他们的执行顺序
这里有一个标准,从这里你可以确定Start是在唤醒后执行的。但是,如果您有多个相同类型的单行为,那么很难跟踪哪个先执行

如果您的问题只是执行顺序,并且您有不同的类型,那么您可以只更新执行顺序

否则,还有更多的方法通过在MonoBehavior中使用工厂方法来避免这两个缺点

考虑在这种情况下,执行顺序为:
唤醒=>oneable=>Reset=>启动=>您的初始化方法

私营工厂法
public class:mono行为
{
//带有相关gameobject和init参数的工厂方法
公共静态YourMono AddWithInit(游戏对象目标,int-yourInt,bool-yourBool)
{
var yourMono=target.AddComponent();
yourMono.initmonobhavior(yourInt,yourBool);
归还你的单子;
}
私人行为(int-yourInt,bool-yourBool)
{
//在这里初始化
}
}
此方法提供了更好的封装,因为我们可以确保只调用一次initMonoBehaviorwioll

扩建厂 也可以从扩展创建工厂。在这种情况下,从类中删除工厂方法,将工厂逻辑与游戏逻辑解耦可能会很有用

但是在这种情况下,您需要将initMonoBehavior设置为内部,并在同一名称空间中实现扩展。
因此,initMonoBehavior将更易于访问(从同一名称空间内部访问),因此它具有更低的封装性

[可序列化]
公共类数据
{
}
名称空间YourMonoNameSpace.MonoBehaviorFactory
{
公共静态类单工厂
{
公共静态YourMono添加YourMono(此游戏对象targetObject,YourData initData)
{
var yourMono=targetObject.AddComponent();
yourMono.initmonobhavior(initData);
归还你的单子;
}
}
}
名称空间名称空间
{
公共课:单一行为
{
private YourData_componentData=null;
内部void initMonoBehavior(YourData initData)
{
if(_componentData!=null)返回;
_componentData=initData;
}
}
}
也就是说,这两种选择都有一个缺点:

  • 有人可能会忘记发射它们
因此,如果您希望此方法是“必需的”,而不是可选的,我建议添加一个bool标志,以确保没有人忘记实现它

控制反转-内部唤醒 就我个人而言,我会用,或用,实现逻辑,我会在唤醒期间调用它,以确保初始化一直被调用

public类YourMonoAutoInit:monoBehavior
{
公共InitLogic\u初始化逻辑;
//带有相关gameobject和init参数的工厂方法
公共图书馆
{
//确保我们没有错过初始化逻辑
Assert.IsNotNull(_initializationLogic);
initMonoBehavior(_initializationLogic);
}
私有void initMonoBehavior(InitLogic initializationLogic)
{
//使用
int request=initializationLogic.currentRequest;
bool playerAlive=初始化逻辑.playerAlive;
}
}
公共类InitLogic:ScriptableObject
{
公共int currentRequest=1;
public bool playersalive=false;
}
//这是另一种可能访问玩家状态并改变它的行为
公共类杀手玩家:单一行为
{
公共逻辑播放状态;
public void KillThisPlayer()=>playerState.playersalive=false;
}
使用最新版本,您将实现控制反转。
因此,与其将数据设置为单一行为,不如:

//将数据从类设置为单行为
公共类OtherScript:MonoBehavior
{
私有void createMonoBehavior()=>YourMono.AddWithInit(gameObject,1,true);
}
您将从类中获取数据

//从类中获取
公共类:单一行为
{
公共数据;
私人空间
{
(int-yourInt,bool-yourBool)=data.GetData();
//对接收到的数据进行处理
}
}

请添加
MyComponent
的代码。您也可能将
go.addComponent(typeof(MyComponent))指定为MyComponent
go.addComponent()
,对吗?总的来说,听起来这个方法已经达到了这个目的,不是吗?代码可能只是一个私有字符串字段,可以在构造函数中设置,构造函数将每次更新的值输出到控制台。因为它是私有的,所以我只能在构造函数中设置它,这就是为什么