Object Oriented Paradigm - C #

My scenario: Consider the two classes class SubGroup and class Group . I do not want other classes to not create a SubGroup's without Group , because SubGroups would not exist without Group . But, a Group can exist without any SubGroup . In addition, a Group may contain several 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. } 

What I tried: I could make Group inherit from SubGroup and make the SubGroup constructor secure, but this says is-a release that each group is a subgroup. But actually it is not.

Also, I want arg to create a subgroup, but I have no arguments for the subgroup during group creation, so I cannot use inheritance.

Inner classes . Inner classes will not help, because I have SuperGroup,SubGroup,MicroGroup many layers. This is actually a financial project, I have Account,AccountHead,SubGroup,Group , etc., Therefore, internal layers can also be created. which will reduce readability.

How can I achieve in C #?

+4
source share
6 answers

Can't create without the specified object? Sounds like a constructor injection to me.

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

Thus, you cannot create a subgroup without a group, and if you pass null, this will result in a runtime exception. Backside? It cannot be serialized and cannot be used in ORM.

Not sure if this meets your requirement.

+5
source

I do not want other classes to not create a SubGroup object other than Group, because SubGroups would not exist without Group.

Why not just invert the dependency in the declaration:

 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; } } 

So, you will use all this as:

 var group = new Group(); var subgroup = Subgroup.Create(group, 2); 
+7
source

You should consider whether or not you really need type differences between the different levels of groups. In many cases, it is enough to simply create a composite template where an object can have several subobjects of the same (or general type). This allows you to place objects in free matter.

Instead, you should consider whether the different levels of the group are really different in behavior. What is the difference between a level 2 group and a level 3 group, for example? Do they share the same behavior, with the exception of the parent and child group level? If so, you should definitely combine them.

Another thing you should consider if you even need a restriction so that no one but the parent group can create a subgroup. Why do you need this? It makes sense to limit that no one but a group can add subgroups to themselves, but creating objects is usually not a problem (instead, it is actually much more useful if you can freely create objects without additional dependencies - this allows you to test it! )

For example, your groups might look like this:

 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); 

You can even make a special subtype that matches your "root" group, and all other groups have a protected constructor and can only be created by their own type (group or root group).

+6
source

You can use interface and declare SubGroup as a private inner class:

 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); } } 

Edit:

If the inner class is not your option, another option you might think of is to split the assembly, in your case you can create one assembly containing only Group , SubGroup and ISubGroup , and declare SubGroup as an internal class:

 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
source

From the description that you give, I would say that you may be misconsidering this problem - you are trying to limit the visibility of the constructor due to restrictions in your program model, but there are other possible solutions.

Some thoughts that alternatives may provide:

  • you want to create a Subgroup if there is a parent of Group , but this does not mean that the class cannot / cannot work in isolation. If a class functions in isolation, you might need to consider that your preferred use is not really a limitation. (This is similar to the argument against the singleton pattern: β€œthere can only be one” and β€œthere is only one.”) What happens if a subgroup was created without a group?

  • Is there an actual relationship from Subgroup to Group ? If so, make it explicit in the constructor. If your constructor is public Subgroup(Group parent) , then you can be sure that no matter where it was created, there will always be a Group .

  • Is there a difference between the two classes? Can you reuse Group in both cases and have an optional parent / child property for the hierarchy, or is there a difference in functionality between the two?

  • Can you use the assembly border to your advantage? You can mark the Subgroup constructor as internal , and then verify that the code inside this assembly matches the intended use.

+1
source

My answer is that you should simply declare as internal all the constructors that you want to hide from external classes.

If you do this, only classes within the same assembly will be able to access them (for example, "class library project").

Other than that, you should follow the recommendations in some other answers that recommend a different architecture.

However, you can make the constructor private and call it through reflection.

Instead of directly accessing the constructor, you can have a private static method in SubGroup that returns the factory method and calls this through reflection. This makes calling the constructor somewhat more difficult (and avoids boxing operations during construction).

I do not recommend doing this; You should find a cleaner way, for example, using the internal constructor or another architecture , but so that you can see how you could do this:

 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; } } 
+1
source

Source: https://habr.com/ru/post/1479727/


All Articles