4

我的场景:考虑两个类class SubGroup,和 class Group。我不希望其他类在SubGroup's没有 的情况下创建对象Group,因为SubGroups没有Group. 但是, Group可以没有任何SubGroup. 此外,Group可以包含多个SubGroup's.

class SubGroup{
  private SubGroup(int arg){
  }

 }

class Group{  
   List<SubGroup> list;
   Group(int param){
     list  = new List<SubGroup>();
   }

   SubGroup createChild(int args){
       return new SubGroup(int args);  // I need to access SubGroups constructor?? (without using inheritance).
   }
 }


 class C{
      Group b = new Group(param);
      SubGroup a = b.createChild(args); // since constructor is not visible here. bcz, SubGroup  will not exist without Group.
 }   

我已经尝试过: 我可以让 Group 从 SubGroup 继承并使 SubGroup 构造函数成为受保护的,但这说明了is-a关系,即每个 Group 都是一个 SubGroup。但实际上并非如此。

此外,我想要一个 arg 来创建一个子组,但在创建组期间我没有子组的参数,因此我不能使用继承。

内部类:内部类无济于事,因为我有SuperGroup,SubGroup,MicroGroup很多层。实际上这是一个金融项目,我有Account,AccountHead,SubGroup,Group等等。所以也可能会创建内层。这会降低可读性。

我如何在 C# 中实现?

4

6 回答 6

7

除了 Group,我不希望其他类创建 SubGroup 的对象,因为没有 Group,SubGroups 将不存在。

为什么不只是在声明中反转依赖项:

class Group{  
   List<SubGroup> list;
   ... 
   public void AddSubgroup(SubGroup sub) {
       list.Add(sub);
   }
 }

class SubGroup{

  ///private ctor, can be used only inside class
  private SubGroup(int arg){
  }

  public static Subgroup Create(Group parent, int arg) {
       Subgroup sub = new Subgroup(arg);//use private ctor
       parent.AddSubgroup(sub);
       return sub;
  }

 }

因此,您将使用以下所有内容:

var group = new Group(); 
var subgroup = Subgroup.Create(group, 2); 
于 2013-05-08T11:48:45.927 回答
6

您应该考虑是否真的需要在不同级别的组之间进行类型区分。在许多情况下,只需构建一个复合模式就足够了,其中一个对象可以有多个相同(或通用)类型的子对象。这使您可以自由地嵌套对象。

相反,您应该考虑您的不同组级别是否实际上在行为上有所不同。例如,2 级组和 3 级组之间有什么区别?除了父子组级别之外,他们是否具有相同的行为?如果是这样,您绝对应该将它们结合起来。

如果您甚至需要限制除父组之外的任何人都不能创建子组,那么您应该考虑的另一件事。为什么你甚至需要那个?限制除组之外的任何人都不能向自身添加子组是有意义的,但对象创建通常不是真正的问题(相反,如果您可以在没有进一步依赖关系的情况下自由创建对象,这实际上会更有帮助 - 这允许您对其进行测试!)。

例如,您的组可能如下所示:

class Group
{
    private List<Group> childs;
    public Group(int arg)
    { ... }

    // pass an existing object
    public void AddSubgroup(Group g)
    {
        childs.add(g);
    }

    // or create the object inside
    public void AddSubgroup(int arg)
    {
        childs.add(new Group(arg));
    }
}

// used like this
Group b = new Group(param);
Group a = new Group(args);
b.AddSubgroup(a);

您甚至可以创建一个与您的“根”组相对应的特殊子类型,并且所有其他组都有一个受保护的构造函数,并且只能由它们自己的类型(组或根组)创建。

于 2013-05-08T11:47:19.807 回答
5

不存在指定对象就不能创建?对我来说听起来像是构造函数注入。

public class SubGroup{
    public SubGroup(Group group){
        if(group == null) {
            throw new InvalidOperationException("A subgroup must has a group");
        }
        this.group = group;
    }
    Group group;
}

这样,您将无法创建没有组的 SubGroup,如果您传递 null,它将引发运行时异常。背面?不能序列化,不能在ORM中使用。

不确定这是否符合您的要求。

于 2013-05-08T11:46:42.783 回答
4

您可以使用interface并声明SubGroup为私有内部类:

public interface ISubGroup
{}

class Group
{
    private class SubGroup : ISubGroup
    {
        public SubGroup(int param)
        {
        }
    }

    List<SubGroup> list;

    public Group(int param)
    {
        list = new List<SubGroup>();
    }

    public ISubGroup createChild(int args)
    {
        return new SubGroup(args); 
    }
}

编辑:

如果内部类不是您的选择,您可以想到的另一种选择是分离程序集,在您的情况下,您可以使一个程序集仅包含Group,SubGroupISubGroup, 并声明SubGroupinternal类:

public interface ISubGroup
{}

internal class SubGroup : ISubGroup
    {
        public SubGroup(int param)
        {
        }
    }

public class Group
{
    List<SubGroup> list;

    public Group(int param)
    {
        list = new List<SubGroup>();
    }

    public ISubGroup createChild(int args)
    {
        return new SubGroup(args); 
    }
}
于 2013-05-08T11:43:22.950 回答
1

根据您提供的描述,我想说您可能以错误的方式看待这个问题 - 由于程序模型的限制,您试图限制构造函数的可见性,但还有其他可能的解决方案。

一些可能提供替代方案的想法:

  • 如果有父级,您只想创建一个,但这并不意味着该类不能/不能单独运行。如果类的功能是孤立的,也许您应该考虑到您的首选用法实际上并不是一个限制。(这类似于反对单例模式的论点:“只能有一个”与“只有一个”。)如果在没有组的情况下创建子组会发生什么?SubgroupGroup

  • Subgroup从到有实际关系Group吗?如果是这样,请在构造函数中使其显式。如果您的构造函数是,public Subgroup(Group parent)那么您可以放心——无论它是在哪里创建的——总会有一个Group关联的。

  • 这两个班级有区别吗?您可以在这两种情况下重用Group并为层次结构提供可选的父/子属性,还是两者之间的功能实际上存在差异?

  • 你能利用装配边界来发挥你的优势吗?您可以将Subgroup构造函数标记为internal,然后确保该程序集中的代码符合其预期用途。

于 2013-05-08T11:53:02.173 回答
1

我的回答是你应该简单地声明internal所有你想对外部类隐藏的构造函数。

如果你这样做,只有同一个程序集中的类(即“类库项目”)才能访问它们。

除此之外,您应该遵循其他一些推荐不同架构的答案中的建议。

但是,可以将构造函数设为私有并通过反射调用它。

或者不是直接调用构造函数,您可以有一个私有静态方法,SubGroup其中返回一个工厂方法,并通过反射调用它。这使得调用构造函数变得不那么繁琐(并且避免了在构造过程中的装箱操作)。

我建议不要这样做;您应该找到一种更简洁的方法,例如使用internal构造函数或不同的架构,但只是为了让您了解如何做到这一点:

using System;
using System.Reflection;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            Group group = new Group();
            SubGroup subGroup = group.MakeSubgroup(42);
            Console.WriteLine(subGroup.Value);
        }
    }

    public sealed class Group
    {
        public SubGroup MakeSubgroup(int value)
        {
            return _subgroupFactory(value);
        }

        static Func<int, SubGroup> getSubgroupFactory()
        {
            var method = (typeof(SubGroup)).GetMethod("getSubgroupFactory", BindingFlags.NonPublic | BindingFlags.Static);
            return (Func<int, SubGroup>) method.Invoke(null, null);
        }

        static readonly Func<int, SubGroup> _subgroupFactory = getSubgroupFactory();
    }

    public sealed class SubGroup
    {
        private SubGroup(int value)
        {
            this.value = value;
        }

        public int Value
        {
            get
            {
                return value;
            }
        }

        static Func<int, SubGroup> getSubgroupFactory()
        {
            return param => new SubGroup(param);
        }

        readonly int value;
    }
}
于 2013-05-08T12:09:55.400 回答