简体   繁体   English

限制类工厂设计模式

[英]Restricted class factory design pattern

Is there an elegant (or any) way to achieve following in C#? 有没有一种优雅的(或任何)方式来实现C#的关注?

  • Let's have a class 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类(进一步ItemBaseItem1Item2 ...),该类不允许直接实例化(非公共构造)-防止用户创建Item*任何“未跟踪”实例。
  • Let's have a non-static class 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*实例(因为它们会跟踪生成的实例并做一些额外的工作)。
  • Let's have an optional requirement: The 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 )。
  • It would be nice if the Manager is not forced to be derivation of Item* . 如果不强制Manager衍生Item*那将是很好的。
  • It would be nice if there is as little reflection as possible. 如果反射越少越好。

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替代方法( internalInternalsVisibleToAttribute都不错),因此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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM