[英]Restricted class factory design pattern
Is there an elegant (or any) way to achieve following in C#? 有没有一种优雅的(或任何)方式来实现C#的关注?
ItemBase
(further derivable to Item1
, Item2
...), which does not allow direct instantiation (non-public construction) - to prevent user to create any 'untracked' instance of Item*
. 让我们拥有一个ItemBase
类(进一步ItemBase
到Item1
, Item2
...),该类不允许直接实例化(非公共构造)-防止用户创建Item*
任何“未跟踪”实例。 Manager
, whose instances (multiple ones allowed) only can create and provide instances of Item*
(because they keep track of produced instances and do some additional work). 我们有一个非静态的类Manager
,其实例(允许多个实例) 只能创建和提供Item*
实例(因为它们会跟踪生成的实例并做一些额外的工作)。 Manager
instances would like to manipulate non-public members of the managed Item
instances (similar like the Manager
would be a friend
of Item*
). 让我们有一个可选的要求: Manager
实例想操纵托管Item
实例的非公共成员(类似于Manager
成为Item*
的friend
)。 Manager
is not forced to be derivation of Item*
. 如果不强制Manager
衍生Item*
那将是很好的。 Notes: 笔记:
If possible, please consider this as a question raising from process of thinking how to implement particular problem solution in a best and elegant way. 如果可能的话,请考虑从如何以最佳,优雅的方式实施特定问题解决方案的过程中提出这个问题。 I would like it to be general and no, I don't have sources and yes, I have already tried some variants, but none of them satisfied my needs. 我希望它是通用的,不,我没有资源,是的,我已经尝试了一些变体,但是没有一个能满足我的需求。 Thank you. 谢谢。
As far as I know, there is no acceptable friend
alternative (any of internal
and InternalsVisibleToAttribute
seems to be good), so the ItemBase
just provides the 'special' (but public) modification methods and the user must be aware, these methods are not for him :o( 据我所知,没有可以接受的friend
替代方法( internal
和InternalsVisibleToAttribute
都不错),因此ItemBase
仅提供了“特殊”(但公共)修改方法,用户必须知道,这些方法不是为他:o(
I like this solution , but I'm not able to invent, how to allow multiple Manager
instances using it. 我喜欢这种解决方案 ,但是我无法发明如何允许多个Manager
实例使用它。
I think this might answer your problem : 我认为这可能会回答您的问题:
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;
}
}
Ok, giving up. 好的,放弃。 If this might help to fully understand the purpose, there is the less bad solution I've (currently) ended up. 如果这可以帮助您充分理解其目的,那么我(目前)最终会找到一种较差的解决方案。 Passing the creation functions is done via static constructors (which are not accessible by the users), unfortunately the ugly thing is their invocation... 传递创建函数是通过静态构造函数(用户无法访问)完成的,不幸的是,丑陋的事情是它们的调用...
Any idea how to make it better? 知道如何使它变得更好吗?
The item definitions: 项目定义:
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;
}
}
The manager: 管理者:
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;
}
}
}
The test: 考试:
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);
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.