想象一下,你正在制作一个使用某种纹理的游戏对象:
public class Action {
//This two can (must) be overriden
public const string _HoverCursor = "Textures/cursors/select";
public virtual string HoverCursor { get { return _HoverCursor; } }
//This is the get texture by string
private static Texture2D cursorTex = null;
public static Texture2D cursor { get { return ResourceManager.loadTexture(ref cursorTex, HoverCursor); } }
}
如果传递了null
,则loadTexture
函数将加载纹理。否则,它只返回原始值。
正如你所看到的,我正在制作一个动作原型。将有类似攻击、移动或构建的操作。我想为每个类定义存储一个(和不同的)纹理对象。当需要使用上面的getter时,这个对象应该是惰性加载的。
既然静态属性不能被覆盖,我如何为所有子实例实现它?
这是loadTexture
:
public static Texture2D loadTexture(ref Texture2D target, string name)
{
if (target == null)
{
target = (Texture2D)Resources.Load(name, typeof(Texture2D));
}
return target;
}
您可以对实例成员使用继承和多态性,并使用静态工厂方法作为外观来简化实现的实例化。
例如
public abstract class Action
{
public abstract void LoadTexture(...);
}
// Since static façade class has a generic type parameter, we're talking
// about a completely different class than just "Action" and both can co-exist!
public static class Action<TAction> where TAction : Action, new()
{
public static Texture2D LoadTexture(...)
{
// Since generic TAction parameter must implement a public parameterless
// constructor, you may instantiate T like a concrete class:
return new TAction().LoadTexture(...);
}
}
因此,您将使用如下静态方法:
Texture2D texture = Action<CustomAction>.LoadTexture2D(...);
您实际上已经自己回答了这个问题:
既然静态属性不能被覆盖,我如何为所有子实例实现它?
只需将属性设置为实例属性即可。例如:
public class Action {
//This two can (must) be overriden
public const string _HoverCursor = "Textures/cursors/select";
public virtual string HoverCursor { get { return _HoverCursor; } }
//This is the get texture by string
private static Texture2D cursorTex = null;
public virtual Texture2D cursor
{
get
{
return ResourceManager.loadTexture(ref cursorTex, HoverCursor);
}
}
}
public class Attack {
//This two can (must) be overriden
public const string _HoverCursor = "Textures/cursors/attack";
public virtual string HoverCursor { get { return _HoverCursor; } }
//This is the get texture by string
private static Texture2D cursorTex = null;
public override Texture2D cursor
{
get
{
return ResourceManager.loadTexture(ref cursorTex, HoverCursor);
}
}
}
每个类仍然只保存一个纹理,但如果每个类都有一个实例,则可以检索该类的正确光标纹理。假设您只需要在有类实例的情况下设置光标,所以这不应该是一个不合理的限制。
请注意,在上文中,如果没有其他代码实际需要HoverCursor
属性,则可以去掉它,使_HoverCursor
常量成为私有成员,然后直接在cursor
属性getter中使用它。
还要注意,这个实现不是线程安全的。只要您总是从一个线程访问cursor
属性,就可以了。但如果不是(或者可能只是为了简单起见),您可能更喜欢使用Lazy<T>
类。例如:
//This is the get texture by string
private static Lazy<Texture2D> cursorTex =
new Lazy<Texture2D>(() => ResourceManager.loadTexture(HoverCursor));
public virtual Texture2D cursor
{
get
{
return cursorTex.Value;
}
}
在此版本中,请注意,loadTexture()
方法已更改为始终加载纹理,因此不需要ref
参数。Lazy<T>
类将确保线程安全的延迟初始化,每个类只调用loadTexture()
一次。