我的情景:
考虑两个类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来创建一个子组,但是在创建Group期间我没有子组的参数,因此我不能使用继承。
内部课程:内部课程无济于事,因为我有SuperGroup,SubGroup,MicroGroup
多层。
实际上这是一个金融项目,我有Account,AccountHead,SubGroup,Group
等。所以也可以创建内层。这将降低可读性。
我怎样才能在C#中实现?
答案 0 :(得分: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);
答案 1 :(得分:6)
您应该考虑是否确实需要在不同级别的组之间进行类型区分。在许多情况下,只需构建一个composite pattern就足够了,其中一个对象可以有多个相同(或常见)类型的子对象。这允许您将对象嵌套在一个自由的事物中。
相反,你应该考虑你的不同群体水平在行为上是否真的不同。例如,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);
您甚至可以创建一个与您的“根”组对应的特殊子类型,并且所有其他组都具有受保护的构造函数,并且只能由它们自己的类型(组或根组)创建。
答案 2 :(得分: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;
}
这样,您将无法创建没有组的子组,如果传递null,则会抛出运行时异常。背面?无法序列化,也无法在ORM中使用。
不确定这是否符合您的要求。
答案 3 :(得分: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
,SubGroup
和ISubGroup
,并将SubGroup
声明为internal
类:
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);
}
}
答案 4 :(得分:1)
根据您提供的描述,我会说您可能以错误的方式查看此问题 - 您试图限制构造函数的可见性,因为程序模型中存在限制,但还有其他可能的解决方案。
可能提供替代方案的一些想法:
如果有Subgroup
个父级,则 想要创建Group
,但这并不意味着该课程没有/不能孤立地运作。如果该类是孤立运行的,也许您应该考虑您的首选用法实际上不是限制。 (这类似于反对单例模式的论点:“只能一个”而“ 只有一个。”)如果创建了一个子组会发生什么没有小组?
是否存在从Subgroup
到Group
的实际关系?如果是这样,请在构造函数中使其显式化。如果您的构造函数是public Subgroup(Group parent)
,那么您可以放心 - 无论它在何处创建 - 总会有Group
关联。
这两个类有区别吗?您是否可以在两种情况下重用Group
并为层次结构提供可选的父/子属性,或者两者之间的功能是否存在差异?
你可以使用装配边界吗?您可以将Subgroup
构造函数标记为internal
,然后确保该程序集中的代码符合其预期用途。
答案 5 :(得分: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;
}
}