It is a not good practice because people expect something when they see the property in the class. Imagine if someone writes:
var n = new Navigation (...);
n.Amount = 123.45;
......
Console.WriteLine(n.Amount); //null? why???
A better approach would be to at least warn them:
public virtual decimal Amount{
get { return new NotSupportedException("Amount is not supported in this class."); }
set { //same as above }
}
But now you'd get the C# practice warning: "properties should behave like fields and should never throw exceptions".
Perhaps you can add a Type
field, then throw away inheritance altogether. But I'm not sure if this is appropriate for your scenario (maybe you have lots of extra fields in derived classes).
Of course, if you're not writing a library that will be used by lots of other programmers, there's nothing wrong to bend common practices. Be flexible.
Do you find it confusing to yourself? If it works and you're comfortable with it, go ahead.
What would I do? This is one of the down sides of Entity Framework, which I don't really like anyway. To me, it brings more problems than it solves. I'd just create tables in the DB, create the classes as you wish in C#, then write some helper methods to map them. If all you do is SELECT
and INSERT
, it's not as hard as you may think. It's outside the scope of this site, but I guarantee you it's around ~50 lines (I've done it).
To me it seems you have a solution looking for a problem.
Is there a name for splitting interfaces by accessors and mutators into separate interfaces?
This might be a little provoking, but actually I would call it "overdesigning things" or "overcomplicating things". By offering a mutable and an immutable variant of the same class, you offer two functionally equivalent solutions for the same problem, which differ only in non-functional aspects like performance behaviour, API and security against side effects. I guess that is because you fear to make a decision which one to prefer, or because you try to implement the "const" feature of C++ in C#. I guess in 99% of all cases it will not make a big difference if the user picks the mutable or the immutable variant, he can solve his problems with the either or the other. Thus "likeliness of a class to be used" is probably result of what you offer in your library - if you offer two almost similar solutions to the same problem, expect a 50% chance that the users will pick variant A or B. If you offer just one solution, the likeliness is high they will use that solution, and will be happy with it.
The exception is when you design a new programming language or a multi purpose framework which is going to be used by some ten thousands of programmers or more. Then it can indeed scale better when you offer immutable and mutable variants of general purpose data types. But this is a situation where you will have thousands of different usage scenarios - which is probably not the problem you face, I guess?
Is splitting them in this way the 'right' approach if they are equally likely to be used or is there a different, more accepted pattern
The "more accepted pattern" is called KISS - keep it simple and stupid. Make a decision for or against mutability for the specific class/interface in your library. For example, if your "StatSet" has a dozen of attributes or more, and they are mostly changed individually, I would prefer the mutable variant and just not modify the base stats where they should not be modified. For something like a Foo
class with attributes X,Y,Z (a three dimensional vector), I would probably prefer the immutable variant.
Are there any immediately foreseeable downsides to using this pattern, save for complicating the interface hierarchy?
Overcomplicated designs make software harder to test, harder to maintain, harder to evolve.
Best Answer
Inheritance (driven to the extreme) is not an efficient approach in modeling something like weapons or enemies in a game. It's quite common to see people thinking about having
Enemy
,FlyingEnemy
,GroundEnemy
, then wanting to add more behaviour and realize that they'd end up withInvisibleFlyingEnemy
and so on.You're trying to decompose your weapon into their sub-parts, then trying to avoid duplication. One could ask you why you have different classes for the weapons, but your
Grip
class is shared by both (i.e. why notBladeGrip
andProjectileGrip
). This can easily result in weird inheritance trees, and in the end none of them really makes you comfortable.Since that doesn't work very well, generally in game development you avoid inheritance and use the Entity-Component-System architecture.
I'm not saying that you shouldn't have any inheritance, but there's no advantage in trying to get a 1-to-1 mapping between classes and what you see in the game. Disadvantages include serious inflexibility when you try to add new things and wasting time working on the invisible inheritance hierarchy instead of the visible game.