Search code examples
c#.netinheritanceoptimizationmultiple-inheritance

How can I optimize the structure of my classes


I am struggling to define the structure of my classes

I created a list of the object of the class ObjMetaClass. Which contains some meta-information about its object points (points: a property of the ObjMetaClass class).
But points can be of two types, one TwoPointsPattern class and the other two ThreePointsPattern class

My concern is that whenever I want to access any item, I first need to check which item is stored in the current item for casting (is it TwoPointsPattern orThreePointsPattern)

List<ObjMetaClass> objList = new List<ObjMetaClass>();
// some items
objList.Add(new ObjMetaClass(new TwoPointsPattern(...), isTwoPointsPattern:true, rate:124));
objList.Add(new ObjMetaClass(new ThreePointsPattern(...), isTwoPointsPattern:false, rate:654));

// access items from list
for (int i = 0; i < objList.Count; i++)
{
    // check for casting object
    if(objList[i].isTwoPointsPattern)
        TwoPointsPattern temp = objList[i].points as TwoPointsPattern;
        /* some logic or function call */
    else
        ThreePointsPattern temp = objList[i].points as ThreePointsPattern;
        /* some logic or function call */
}

Is there a better way to improve it or avoid if checks? Any suggestions, please

Structures of classes
ObjMetaClass

public class ObjMetaClass
{
    public object points { get; internal set; }
    public bool isTwoPointsPattern { get; internal set; }
    internal int rate { get; set; }

    public ObjMetaClass(object points, bool isTwoPointsPattern, int rate)
    {
        // check expected type of points object
        if (points.GetType() != typeof(TwoPointsPattern) &&
            points.GetType() != typeof(ThreePointsPattern))
            throw new ArgumentException("Expected types TwoPointsPattern and ThreePointsPattern");

        this.points = points;
        this.isTwoPointsPattern = isTwoPointsPattern;
        this.rate = rate;
    }
}

TwoPointsPattern and ThreePointsPattern

public class TwoPointsPattern
{
    public double FirstDate { get; internal set; }
    public double FirstPrice { get; internal set; }

    public double SecondDate { get; internal set; }
    public double SecondPrice { get; internal set; }

    public TwoPointsPattern(double FirstDate, double FirstPrice, double SecondDate, double SecondPrice)
    {
        this.FirstDate = FirstDate;     this.FirstPrice = FirstPrice;
        this.SecondDate = SecondDate;   this.SecondPrice = SecondPrice;
    }
}

public class ThreePointsPattern
{
    public double FirstDate { get; internal set; }
    public double FirstPrice { get; internal set; }

    public double SecondDate { get; internal set; }
    public double SecondPrice { get; internal set; }

    public double ThirdDate { get; internal set; }
    public double ThirdPrice { get; internal set; }

    public ThreePointsPattern(double FirstDate, double FirstPrice, double SecondDate, double SecondPrice,
                              double ThirdDate, double ThirdPrice)
    {
        this.FirstDate = FirstDate;     this.FirstPrice = FirstPrice;
        this.SecondDate = SecondDate;   this.SecondPrice = SecondPrice;
        this.ThirdDate = ThirdDate;     this.ThirdPrice = ThirdPrice;
    }
}

Solution

  • First approach - inheritance:

    public class TwoPointsPattern
    {
      public double FirstDate { get; internal set; }
      public double FirstPrice { get; internal set; }
    
      public double SecondDate { get; internal set; }
      public double SecondPrice { get; internal set; }
    
      public TwoPointsPattern(double FirstDate, double FirstPrice, double SecondDate, 
        double SecondPrice)
      {
          this.FirstDate = FirstDate;     this.FirstPrice = FirstPrice;
          this.SecondDate = SecondDate;   this.SecondPrice = SecondPrice;
      }
    
      public virtual void DoSomeLogic()
      {...}
    }
    
    public class ThreePointsPattern : TwoPointsPattern
    {
       public double ThirdDate { get; internal set; }
       public double ThirdPrice { get; internal set; }
    
       public ThreePointsPattern(double FirstDate, double FirstPrice,
                 double SecondDate, double SecondPrice,  double ThirdDate, double ThirdPrice) 
               : base(FirstDate, FirstPrice, SecondDate, SecondPrice) 
       {
          this.ThirdDate = ThirdDate;     this.ThirdPrice = ThirdPrice;
       }
    
       public override void DoSomeLogic()
       {...}
    }
    
    public class ObjMetaClass
    {
       public TwoPointsPattern points { get; internal set; }
       ...
     }
    
    // access items from list
    for (int i = 0; i < objList.Count; i++)
    {
       objList[i].points.DoSomeLogic();
    }
    

    Second approach - interfaces:

    public interface ISomeLogic
    {
       void DoSomeLogic();
    }
    
    public class TwoPointsPattern : ISomeLogic
    {
       public void DoSomeLogic();
    }
    
    public class ThreePointsPattern : ISomeLogic
    {
       public void DoSomeLogic();
    }
    
    public class ObjMetaClass
    {
        public ISomeLogic points { get; internal set; }
        ...
    }
    
    // access items from list
    for (int i = 0; i < objList.Count; i++)
    {
        objList[i].points.DoSomeLogic();
    }
    

    From the code you shown looks like ThreePointsPattern can be a child for the TwoPointsPattern so 1st approach would be better, if I didn't miss anything.