0

In a C# ASP.Net Core Web Application I have a Domain Model CentralDesignObject made up of many component objects & properties, producing a significant amount of derived/calculated values.

This CentralDesignObject includes a reference to a DesignType object. This DesignType determines various fundamental characteristics of the design object, and various calculated values of the design type may have different calculations based on the DesignType. The component objects/properties that make up the CentralDesignObject remain consistent across design types.


    CentralDesignObject{
    
      public Guid DesignObjectId {get; set;}
    
      public int DesignTypeId {get; set;}
      [ForeignKey("DesignTypeId")] 
      public DesignType {get; set;}
        
      public ICollection<RelatedDataA> RelatedDataA {get; set;}
    
      public ICollection<RelatedDataB> RelatedDataB {get; set;}
    
      public CalculationMethod_X() {
      
        if (DesignType.Name == 'foo') {  
          // do x
          return x;
          } else if (DesignType.Name == 'bar') {
          // do y
          // Slightly different result
          return y;
          }
        }
    }

Currently the number of design types is small, and where the DesignType may have an effect on calculations, looping and applying conditional logic based on this type is relatively effective.

The current structure puts CentralDesignModels in a single database table which is straightforward/simple for querying these CentralDesignModels in various areas of the web-application.

It seems as though separating CentralDesignModels of the various DesignTypes into individual concrete types would provide benefit through compartmentalization of logic. A way of achieving that could be to be making the CentralDesignModels into an interface from which the specific types of CentralDesignModels inherit. However this seems as though this would complicate other areas of the web-application such as the database structure and querying mechanisms.

What approach do you think would be most valid in this situation? Does the current approach appear valid or problematic? Is there a clear way / design pattern that would allow me to organize this data so that the database structure may remain simple, while the logic of the various DesignTypes may be compartmentalized in discrete classes?

Any pointers or references no matter how basic or fundemental are appreciated, thank you.

5
  • why is your function linked to the db structure? can't you get the same properties out of the db and create various CentralDesignObject_X CentralDesignObject_Y etc based on the type?
    – Ewan
    Commented Sep 8, 2023 at 19:43
  • That certainly seems possible. I have other separate (Business Logic) classes further down the logic flow which currently take CentralDesignObject as a constructor parameter, for example a text document writer class. Would the approach here be to refactor those classes constructor parameters replacing CentralDesignObject with an Interface from which CentralDesignObject_X and CentralDesignObject_Y inherit?
    – freedomdev
    Commented Sep 8, 2023 at 21:48
  • Why not simply inherit from CentralDesignObject? I guess what i'm saying is you don't really say what the problem you are having is. You want the best design for your system, but its probably too complex to explain fully in a question. Unless you have a specific pain point that you can explain, its hard to guess what a good answer is. ie. stop using EF, its the cause of all your problems.
    – Ewan
    Commented Sep 8, 2023 at 22:17
  • That is all quite reasonable. I would say that what I am trying to achieve is avoiding bloated looping logic in the domain models as the number of design types potentially increases over time, and by doing so provide a better separation of logic for somewhat long calculation routines, while maintaining the simplicity of the core singular domain model for CRUD operations on the components of the domain model. Thank you for your consideration none the less.
    – freedomdev
    Commented Sep 8, 2023 at 22:34
  • I understand what you mean, but you are clearly aware of the various options, inheritance, injection, ADM etc I don't want to write an answer that simply enumerates them and their various pros and cons. If it was more of a "I tried X but couldnt get Y to work" or something then you might get a "this is how i made Y work" answer
    – Ewan
    Commented Sep 9, 2023 at 10:11

1 Answer 1

0

This DesignType determines various fundamental characteristics of the design object, and various calculated values of the design type may have different calculations based on the DesignType. The component objects/properties that make up the CentralDesignObject remain consistent across design types.

This is a perfect use case for an abstract class.


What C# Object Composition strategy would you apply

That's not the problem. Polymorphism is the problem. When we are hard coding objects' type differentiation that's a symptom of missing polymorphism.


making the CentralDesignModels into an interface from which the specific types of CentralDesignModels inherit.

NOTE: I assume that by "interface" you mean the C# keyword interface thingy.

inherit

Interfaces are implemented, classes are inherited. In other words you still need to inherit from a class. Interfaces do not facilitate nor enhance inheritance.

inheritance is not a (C# keyword) interface

I assume you want to put all these polymorphic methods in an interface. All interface members are public but I bet most of those polymorphic calculations should not be.

If methods must be called in a certain order and/or within a larger control flow only a class can do that. If you do not provide the default implementation for this then sometime in the future I guarantee, repeat GUARANTEE, there will be a huge pile of regret as 15, let's say, subclass implementations don't work in the same way because they were all independently implemented from scratch - because they "inherited from an interface".

inheritance is the fundamental object oriented polymorphism mechanism

  • it defines its public interface by itself
  • it defines the required and optional overrides
  • it embodies the Liskov Substitution Principle, i.e. Strong Behavioral Subtyping

An abstract class is what you need. If you also need base-type objects then give the abstract class the necessary default (override-able as needed) base class implementation.

Public, private, or protected, the abstract class can require sub-class method implementation - with the desired access level. It defines the class public interface by itself without any help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.