I have a class that contains both primitive and custom properties:
public class Version_1
{
public string Name { get; set; }
public int Age { get; set; }
public WeirdDad Weird { get; set; }
public MysteriousDad Mysterious { get; set; }
}
In the future i want to extend the class with a int property plus a customization of one of my custom objects, in this way:
public class Version_2 : Version_1
{
public string IdentityCode { get; set; }
public WeirdChild Weird { get; set; }
}
In Version_2 class the look of WeirdDad object has been replaced with its child WeirdChild so i want to substitute it. In this example, instead, i will have in the Version_2 class both WeirdDad and WeirdChild.
How would you implement this example?
I believe what you want to do is called method hiding. Your Version_2 class should look like this:
public class Version_2 : Version_1
{
public string IdentityCode { get; set; }
public new WeirdChild Weird { get; set; }
}
When you want to access the 'Weird' property from Version_1, you will have to make a call to base.Weird
Make note however that this is not recommended and is a code smell.
IMHO, Version_2 should not inherit Version_1 as it cannot behave totally like Version_1 :
Version_2 version_2Instance = new Version_2();
version_2Instance.Weird = new WeirdDad();
Never forget that inheritance assumes that you are extending base class, not modifing it.
How about using template class and a base abstract class :
public abstract class VersionBase<T>
{
public string Name { get; set; }
public int Age { get; set; }
public abstract T Weird { get; set; }
public MysteriousDad Mysterious { get; set; }
}
Then:
public class Version_1 : VersionBase<WeirdDad>
{
public override WeirdDad Weird { get; set; }
}
public class Version_2 : VersionBase<WeirdChild>
{
public string IdentityCode { get; set; }
public override WeirdChild Weird { get; set; }
}
Think inheritance + polymorphism
Here's some code, I'll make points after ...
public abstract class WeirdPerson() {
public virtual void DoThis() {
// base / default implementation as desired
}
public virtual void DoThat() { // ditto }
public abstract void GoWildAndCrazy;
}
public class WeirdChild : WeirdPerson {
public override void DoThis() { // weird child behavior}
// etc.
}
public class WeirdDad : WeirdPerson {
// override and add methods as needed.
}
public class Version_1
{
public string Name { get; protected set; }
public int Age { get; protected set; }
public WeirdPerson WeirdFamilyMember { get; protected set; }
public MysteriousDad Mysterious { get; protected set; }
public Version_1 (WeirdChild child, string name, int age, MysteriousDad Dad) {
}
}
public class Version_2 : Version_1 {
public Version_2 (WeirdDad dad, string name, int age, MysteriousDad grandfather) : base (dad, name, age, grandfather) {}
}
WeirdPerson
- a more general concept that defines basic stuff for all sub-types.
Name
- inheritance
override
default behavior (methods) - polymorphism
public class WeirdDad : WeirdChild
Version_1
, Version_2
constructors force the client to provide the proper WeirdPerson
sub-type.interface
abstract
class allows us to have default behavior (methods) and default state (properties)public
methods and properties of any class is an interface in the general sense. We do not need to have (C# keyword) interface
in order to follow the principle code to interfaces not implementation
abstract
methods force sub-class implementation. just. like. an. interface
.new
Additional Refactoring
Make the Version
heirarchy parallel the WeirdPerson
heirarchy
Assuming this fits into your design. I think, a year from now you'll be glad you did.
public abstract class Version_X {
// all the original properties here.
// virtual and abstract methods as needed
// LOOK! standard-issue constructor!
protected Version_X ( WeirdPerson person, ...) { // common validation, etc. }
}
public class Version_1 : Version_X {
public Version_1( WeirdChild child, ... ) : base ( child, ... ) {}
}
public class Version_2 : Version_X {
public Version_2 ( WeirdDad dad, ... ) {}
}
Edit - Motivated by comment discussion with DVK
The least knowledge principle says a client should not have to know internal details to use a class. Needing to know how to compose the correct Version
and Weird
is a violation, one could argue.
Let's pretend that a default constructor, for Visitor
let's say, is necessary elsewhere in the overall design. Allowing this means a client can control the Version
/Weird
composition.
Abstraction - loose coupling - is in the abstract
classes. Concrete classes must necessarily be correctly composed so "strong coupling" is inherent in creating concrete objects (the explicit-type constructor parameters), but the underlying loose coupling allows for desired flexibility.
public enum WeirdFamily { Child, Dad, Mother, TheThing }
public static class AdamsFamilyFactory () {
public static Version_X Create (WeirdFamily familyMember) {
switch (familyMember) {
case Dad:
return BuildAdamsDad();
// . . .
}
}
}
public static class MunstersFactory() { // Munsters implementation }
// client code
List<Version_X> AdamsFamily = new List<Version_X>();
Version_X Pugsly = AdamsFamilyFactory.Create(WeirdFamily.Child);
AdamsFamily.Add(Pugsly);
List<Version_X> Munsters= new List<Version_X>();
Version_X Eddie= MunstersFactory.Create(WeirdFamily.Child);
Munsters.Add(Eddie);
DoTheMonsterMash(Munsters);
DoTheMonsterMash(AdamsFamily);
public void DoTheMonsterMash(List<Version_X> someWeirdFamily {
foreach (var member in someWeirdFamily)
member.GoWildAndCrazy();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With