受限类工厂设计模式
本文关键字:设计模式 工厂 | 更新日期: 2023-09-27 18:12:16
是否有一种优雅的(或任何)方式在c#中实现以下功能?
- 让我们有一个类
ItemBase
(进一步衍生为Item1
,Item2
…),它不允许直接实例化(非公开构造)-防止用户创建任何"未跟踪"的Item*
实例。 - 让我们有一个非静态类
Manager
,它的实例(允许多个)只有可以创建和提供Item*
的实例(因为它们跟踪生成的实例并做一些额外的工作)。 - 让我们有一个可选的需求:
Manager
实例希望操作托管Item
实例的非公共成员(类似于Manager
将是Item*
的friend
)。 - 如果
Manager
不是强制Item*
的派生,那就太好了。 - 反射越少越好。
指出:
-
如果可能的话,请将此视为思考如何以最佳和优雅的方式实现特定问题解决方案的过程中提出的问题。我希望它是一般的,不,我没有来源,是的,我已经尝试了一些变体,但没有一个满足我的需求。谢谢你。
-
据我所知,没有可接受的
friend
替代方案(internal
和InternalsVisibleToAttribute
中的任何一个似乎都很好),因此ItemBase
只是提供了"特殊"(但公共)修改方法,用户必须意识到,这些方法不适合他:o( -
我喜欢这个解决方案,但我无法发明,如何允许多个
Manager
实例使用它
我想这可能会回答你的问题:
public class ItemBase
{
protected ItemBase()
{
}
public void PublicMethod() { }
public int PublicProperty { get; set; }
}
public class Factory
{
private class PrivateItemBase : ItemBase
{
public void PrivateMethod() { }
public int PrivateProperty { get; set; }
}
public Factory(int id)
{
}
public IEnumerable<ItemBase> Items { get; private set; }
public ItemBase CreateItem()
{
PrivateItemBase rValue = new PrivateItemBase();
rValue.PrivateMethod();
rValue.PrivateProperty = 4;
return rValue;
}
}
好吧,放弃。如果这可能有助于完全理解目的,那么我(目前)给出了一个不那么糟糕的解决方案。传递创建函数是通过静态构造函数完成的(用户无法访问),不幸的是,丑陋的事情是它们的调用…
有什么好办法吗?
条目定义:
namespace SpecialFactory
{
public enum ItemType
{
Item1,
Item2,
// ... Anyone deriving the Item* should add an item here
}
public abstract class ItemBase
{
public abstract ItemType Id {get;}
public static void RegisterAllCreators()
{
// Force static constructors invocation
var it = Item1.ClassId | Item2.ClassId; // Anyone deriving the Item* should ensure invocation of Manager.RegisterCreator
}
}
public class Item1 : ItemBase
{
static Item1()
{
Manager.RegisterCreator(ItemType.Item1, () => new Item1());
}
protected Item1()
{
}
public static ItemType ClassId => ItemType.Item1;
public override ItemType Id => ClassId;
}
public class Item2 : ItemBase
{
static Item2()
{
Manager.RegisterCreator(ItemType.Item2, () => new Item2());
}
protected Item2()
{
}
public static ItemType ClassId => ItemType.Item2;
public override ItemType Id => ClassId;
}
}
经理:
namespace SpecialFactory
{
public class Manager
{
static Manager()
{
ItemBase.RegisterAllCreators();
}
protected static Dictionary<ItemType, Func<ItemBase>> creators = new Dictionary<ItemType, Func<ItemBase>>();
protected readonly List<ItemBase> managedItems = new List<ItemBase>();
protected ItemBase CreateItem(ItemType type)
{
ItemBase item = null;
if (creators.ContainsKey(type))
{
if ((item = creators[type]()) != null)
managedItems.Add(item);
}
return item;
}
public static void RegisterCreator(ItemType type, Func<ItemBase> creator)
{
if (!creators.ContainsKey(type))
creators[type] = creator;
}
public Manager()
{
}
public ItemBase Test(ItemType type)
{
// var notAllowed = new Item1();
var allowed = CreateItem(type);
return allowed;
}
}
}
测试:namespace SpecialFactory
{
class Program
{
static void Main(string[] args)
{
var m1 = new Manager();
var m2 = new Manager();
var i1 = m1.Test(ItemType.Item1);
var i2 = m2.Test(ItemType.Item2);
}
}
}