私有静态列表是否是限制 class 实例集的适当方法
Is a private static list an appropriate way of limiting the set of instances of a class
我试图避免使用相同的内部数据创建 class 的多个实例。我尝试了一个带有单独 class 的实现来构建 MCode,但试图保护 MCode 构造函数没有用,所以我又回到了这个实现。我想知道这是好的设计还是有什么更好的解决方案?
public class MCode : IEquatable<MCode>
{
private readonly static List<MCode> Instances;
public AEnum AE { get; }
public byte C { get; }
public BEnum BE { get; }
public static MCode GetMCode(AEnum ae, BEnum be, byte c)
{
if (Instances==null)
{
Instances = new List<MCode>();
var newmc = new MCode(ae, be, c);
Instances.Add(newmc);
return newmc;
}
var mc = Instances.Find(x => x.Equals(ae, be, c));
if (mc == null)
{
var newmc = new MCode(ae, be, c);
Instances.Add(newmc);
return newmc;
}
return mc;
}
protected MCode(AEnum ae, BEnum be, byte c)
{
AE = ae;
BE = be;
C = c;
}
public new bool Equals(MCode mc)
{
return (GetHashCode() == mc.GetHashCode());
}
public new bool Equals(AEnum ae, BEnum be, byte c)
{
return (GetHashCode() == GetHashCode(ae, be, c));
}
public new int GetHashCode()
{
return ((byte)AE * 256 * 256 + (byte)BE * 256 * C);
}
public static int GetHashCode(AEnum ae, BEnum be, byte c)
{
return ((byte)ae * 256 * 256 + (byte)be * 256 * c);
}
}
这样做的动机是我有多个包含相同 MCode 属性 的 classes 实例,我希望它们都使用相同的只读 MCode 实例。
您所描述的看起来是 Flyweight Factory pattern。享元 class 是相对较小的,并且 "unique" 对象的数量是有限的,因此维护唯一实例的目录有助于减少内存中不必要的重复数据。
一个例子是US State
。只有 50 个唯一状态,因此将 50 个状态的集合作为一组唯一实例可能会在系统中有所不同,例如,每个用户记录都需要一个状态。
我也会将 class 与工厂分开。使工厂成为一个单独的 class,并为 MCode
internal
创建构造函数(而不是 protected
.
我也会注意您的 Equals
实施。仅仅因为两个对象具有相同的哈希码并不意味着它们是相等的。在你的情况下可能是真的,因为你有有限数量的对象可以被 int
space 覆盖,但它看起来很奇怪。实施 actual Equals
逻辑(您已经在列表查找中)也将不需要重复的 GetHashCode
方法。
您可以使用工厂方法和静态字典来实现:
public class MyType
{
private readonly static Dictionary<int, MyType> instances
= new Dictionary<int, MyType>();
public static MyType CreateNew(int id)
{
if (instances.TryGetValue(id, out var instance)
return instance;
return new MyType(id);
}
private MyType(int id) { ... }
public int UniqueId { get; }
}
如果您的唯一标识符比 int
更复杂,我会简单地实现一个具有值相等语义的私有嵌套 struct/class 并将其用作字典的键。
我试图避免使用相同的内部数据创建 class 的多个实例。我尝试了一个带有单独 class 的实现来构建 MCode,但试图保护 MCode 构造函数没有用,所以我又回到了这个实现。我想知道这是好的设计还是有什么更好的解决方案?
public class MCode : IEquatable<MCode>
{
private readonly static List<MCode> Instances;
public AEnum AE { get; }
public byte C { get; }
public BEnum BE { get; }
public static MCode GetMCode(AEnum ae, BEnum be, byte c)
{
if (Instances==null)
{
Instances = new List<MCode>();
var newmc = new MCode(ae, be, c);
Instances.Add(newmc);
return newmc;
}
var mc = Instances.Find(x => x.Equals(ae, be, c));
if (mc == null)
{
var newmc = new MCode(ae, be, c);
Instances.Add(newmc);
return newmc;
}
return mc;
}
protected MCode(AEnum ae, BEnum be, byte c)
{
AE = ae;
BE = be;
C = c;
}
public new bool Equals(MCode mc)
{
return (GetHashCode() == mc.GetHashCode());
}
public new bool Equals(AEnum ae, BEnum be, byte c)
{
return (GetHashCode() == GetHashCode(ae, be, c));
}
public new int GetHashCode()
{
return ((byte)AE * 256 * 256 + (byte)BE * 256 * C);
}
public static int GetHashCode(AEnum ae, BEnum be, byte c)
{
return ((byte)ae * 256 * 256 + (byte)be * 256 * c);
}
}
这样做的动机是我有多个包含相同 MCode 属性 的 classes 实例,我希望它们都使用相同的只读 MCode 实例。
您所描述的看起来是 Flyweight Factory pattern。享元 class 是相对较小的,并且 "unique" 对象的数量是有限的,因此维护唯一实例的目录有助于减少内存中不必要的重复数据。
一个例子是US State
。只有 50 个唯一状态,因此将 50 个状态的集合作为一组唯一实例可能会在系统中有所不同,例如,每个用户记录都需要一个状态。
我也会将 class 与工厂分开。使工厂成为一个单独的 class,并为 MCode
internal
创建构造函数(而不是 protected
.
我也会注意您的 Equals
实施。仅仅因为两个对象具有相同的哈希码并不意味着它们是相等的。在你的情况下可能是真的,因为你有有限数量的对象可以被 int
space 覆盖,但它看起来很奇怪。实施 actual Equals
逻辑(您已经在列表查找中)也将不需要重复的 GetHashCode
方法。
您可以使用工厂方法和静态字典来实现:
public class MyType
{
private readonly static Dictionary<int, MyType> instances
= new Dictionary<int, MyType>();
public static MyType CreateNew(int id)
{
if (instances.TryGetValue(id, out var instance)
return instance;
return new MyType(id);
}
private MyType(int id) { ... }
public int UniqueId { get; }
}
如果您的唯一标识符比 int
更复杂,我会简单地实现一个具有值相等语义的私有嵌套 struct/class 并将其用作字典的键。