Question for an experienced C# developer
5 years ago
Let's say you're trying to represent any building made of multiple different materials or parts. A single part has any number of mutual references to other parts on any given side on the 3 axes, and some parts can only be attached to other specific parts. For example, wood can be attached above stone, but stone cannot be attached above wood. Another example: A stone arch part can be attached above a window which can then have a stone part above it, but a flat stone part cannot be attached above a window.
Is it bad practice to represent this with a number of empty interfaces with constraints? Like the following, you'd have a base interface for everything:
IAttachablePart
Then you would have a number of interfaces which inherit IAttachablePart such as IAttachableWindow, IAttachableWood and IAttachableStone.
Then you might distinguish even further by having more interfaces that inherit one of those which themselves inherit from IAttachablePart, i.e.; for IAttachableStone:
IAttachableStoneArch, IAttachableStoneWall
Then in the concrete classes (as in implementation classes, not the material concrete) you could enforce the constraints described at the beginning of this post and do something like the following (which totally disregards the previous examples but please ignore that):
public class PlywoodPart : INonLoadBearingPart
{
public List<IStructuralPart> AttachmentsBelow;
public List<ILowMassPart> AttachmentsAbove;
...
}
So why bother doing this? Well, it allows you to create implicit constraints on the structure of a... Structure, and doesn't require any complex conditional logic that would grow increasingly complex to the point of being unmanageable. Also, if a hypothetical developer tried to do anything forbidden with it, the problem would be picked up by the IDE well before any manually thrown exception at runtime that could happen in any edge cases. Performance might also be better than any of the previously mentioned conditional logic in an alternative approach. Here are some problems I might see with this approach:
• You might need to remove a constraint because it makes sense to not have the constraint in one situation, but by removing the constraint you unwittingly make it possible to do something illogical elsewhere.
• It could make it difficult to enforce rules about neighbours of neighbours. If you don't do so, you could have situations where you have a stone arch above a free-standing window, which then has a tower of stone above it that couldn't realistically be supported above a window. But if you try to take this into account, the code could violate the law of demeter (by forcing you to do something like "if (below.below.below is IAttachableWindow) { ... }"
• The amount of interfaces shit starts inheriting could become confusing or outright nonsensical if it isn't done in a clear way
• The apparent bonus benefit that might appear to exist having avoided all the conditional logic, might be an illusion and all that has happened is that the inner workings of C# mean a runtime overhead to make sure all the constraints are satisfied.
Anyone understand enough of my bullshit to have an opinion?
Is it bad practice to represent this with a number of empty interfaces with constraints? Like the following, you'd have a base interface for everything:
IAttachablePart
Then you would have a number of interfaces which inherit IAttachablePart such as IAttachableWindow, IAttachableWood and IAttachableStone.
Then you might distinguish even further by having more interfaces that inherit one of those which themselves inherit from IAttachablePart, i.e.; for IAttachableStone:
IAttachableStoneArch, IAttachableStoneWall
Then in the concrete classes (as in implementation classes, not the material concrete) you could enforce the constraints described at the beginning of this post and do something like the following (which totally disregards the previous examples but please ignore that):
public class PlywoodPart : INonLoadBearingPart
{
public List<IStructuralPart> AttachmentsBelow;
public List<ILowMassPart> AttachmentsAbove;
...
}
So why bother doing this? Well, it allows you to create implicit constraints on the structure of a... Structure, and doesn't require any complex conditional logic that would grow increasingly complex to the point of being unmanageable. Also, if a hypothetical developer tried to do anything forbidden with it, the problem would be picked up by the IDE well before any manually thrown exception at runtime that could happen in any edge cases. Performance might also be better than any of the previously mentioned conditional logic in an alternative approach. Here are some problems I might see with this approach:
• You might need to remove a constraint because it makes sense to not have the constraint in one situation, but by removing the constraint you unwittingly make it possible to do something illogical elsewhere.
• It could make it difficult to enforce rules about neighbours of neighbours. If you don't do so, you could have situations where you have a stone arch above a free-standing window, which then has a tower of stone above it that couldn't realistically be supported above a window. But if you try to take this into account, the code could violate the law of demeter (by forcing you to do something like "if (below.below.below is IAttachableWindow) { ... }"
• The amount of interfaces shit starts inheriting could become confusing or outright nonsensical if it isn't done in a clear way
• The apparent bonus benefit that might appear to exist having avoided all the conditional logic, might be an illusion and all that has happened is that the inner workings of C# mean a runtime overhead to make sure all the constraints are satisfied.
Anyone understand enough of my bullshit to have an opinion?
strength of each part. Then have the computer do an analysis of the structure and determine the total forces applied to each part to see if the structure is good to go. This would help not having a nightmare of updating the growing network of rules and all the potential chances of introductions bugs. Basically making a simple building physics simulator.
Now with this you can use something like a graph system to show which part is connected to which part so a window doesn't actually have to support anything. So you need some kind of edge data to tell the computer where to direct the forces. For example with the rule set you gave as an example about stone not being above wooden window would mean couldn't build things like castles. As this system would allow you to direct the forces safely around the window to more suited load bearing parts.
Admittedly this is more of an analogy for a similar problem I'm thinking of how to solve, but it seems I didn't think through the analogy enough as what would apply to the actual situation I currently have versus the analogy.
Still, your idea is something to consider for a project that I haven't touched for a while. Thanks for continually interacting with me and giving your honest thoughts. I hope your own projects are going well these days.
So have an interface that all parts use so that we can get information we need to test out the rules
Then make a separate interface for the rules to read the node network data to look for any rule breaking pattern. But class using this interface must only check for one rule at a time
Then have a class that stores all this rules in an array you want to test your dataset for.
Something like this
Class RuleTesterForParts{
Node RootNodeOfParts;
Array<PartRuleInterface>Rules;
Class RuleTesterForParts(){
Rules.Push(new NoStoneOverWood());
Rules.Push(new DontMixGreenAndBlueWalls());
Rules.push(new NeedsTopPartToBeRoof());
}
function TestRules(){
For(i=0;i<Rules.length;++i){
If(Rules[i].IsThisRuleBroken(RootNodeOfParts)){// Code for if a rule broke}
Else{// rule was not broken}
}
}
}
My idea for this was to make sure it was easy to find where the rules were made and how they are used.