I've been reading a lot about composition and trying to figure how I can refactor my inheritance tree using composition. Currently my class looks like this:
public abstract class BaseClass
{
public abstract string displayText { get; }
public abstract List<Parameter> parameters { get; }
public abstract void FireEvent();
}
public abstract class SubClass<T> : BaseClass
{
private string _displayText;
public override string displayText { get { return _displayText; } }
private List<Parameter> _parameters;
public override List<Parameter> parameters { get { return _parameters; } }
private T _value; // ADDED TO SUBCLASS
public abstract Event<T> Evt { get; } // ADDED TO SUBCLASS
public override void FireEvent()
{
Evt.Raise(_value);
}
}
public class IntClass : SubClass<int>{}
public class StringClass : SubClass<string>{} // more subclasses like this
From my understanding, there is both inheritance and composition going on here.
SubClass Has-A: (Composition)
List of Parameters
Field for Event
Behaviour of Event<T> which is called within it's own FireEvent method
SubClass Is-A: BaseClass (Inheritance)
IntClass/StringClass Is-A: SubClass & BaseClass
The reason for creating BaseClass is because I need polymorphic lists. This way I can create a List<BaseClass> and call FireEvent() on each element in the list and access the displayText and List<Parameter> in a loop.
In the future I will need a sub class which doesn't have an Event and a subclass which will accept a parameter in FireEvent(). Other variants might crop up.
How would I replace my current structure entirely with a composition based approach? Is it even doable?
In this example, you have 3 behaviors. Int uses 3, String uses only 2. If you put the code like this, when you change AnotherServiceB, you don't need to be worry about it break String (since String doesn't have that service)
public class FireEventService<T>
{
private T _value; // ADDED TO SUBCLASS
public abstract Event<T> Evt { get; } // ADDED TO SUBCLASS
public override void FireEvent()
{
Evt.Raise(_value);
}
}
public class AnotherService
{
}
public class AnotherServiceB
{
}
public abstract class SubClass<T> : BaseClass
{
private readonly FireEventService<T> _fireEventService;
private readonly AnotherService _anotherService;
private string _displayText;
public override string displayText { get { return _displayText; } }
private List<Parameter> _parameters;
public override List<Parameter> parameters { get { return _parameters; } }
public SubClass(FireEventService<T> fireEventService, AnotherService anotherService)
{
// All those services should use with interface and Dependency Injection
_fireEventService = fireEventService;
_anotherService = anotherService;
}
public void FireEvent() => _fireEventService.FireEvent();
}
public class IntClass : SubClass<int>
{
private readonly AnotherServiceB _anotherServiceB;
public IntClass(FireEventService<int> fireEventService, AnotherService anotherService, AnotherServiceB anotherServiceB)
: base(fireEventService, anotherService)
{ }
public void DoSomethingUsingServiceB()
{
//_anotherServiceB.DoSomething();
}
}
public class StringClass : SubClass<string>
{
public StringClass(FireEventService<string> fireEventService, AnotherService anotherService)
: base(fireEventService, anotherService)
{ }
}
Related
I am calling the base constructor but somehow I need to point to the child one back. Take a look at the example bellow:
//Child
public CompanyEventsView(IAggregator aggregator, IRepository<CompanyEvents> repository, int i)
: base(aggregator, repository, i)
{
}
//Base
public BaseViewModelFor(IAggregator aggregator, IRepository<TSource> repository, int i)
{
Aggregator = aggregator;
var source = repository.GetKey(i);
this.MapFromSourceObject(source); // So "This" here should be pointing to the child class
}
Is there any way of doing this?
this and base do not refer to different instances, they are the same.
If your MapFromSourceObject method is defined in the child class, you can cast this to the child type like: (this as CompanyEventsView).MapFromSourceObject(source).
But this would defeat the whole point of inheritance.
Maybe define MapFromSourceObject as abstract or virtual in the base class?
If your base class depends the implementations of child classes, making the class itself abstract would be a better idea.
Maybe this example helps you a little bit with inheritance:
namespace CSharpConsoleApplication.Tests
{
using System;
using System.Collections.Generic;
using System.Linq;
class TemporaryTest
{
public static void Run()
{
Mother<FirstCompanyEvent> firstChild = new FirstChild(new FirstCompanyEvent("this is wrong"));
firstChild.Print();
Mother<SecondCompanyEvent> intChild = new SecondChild(new SecondCompanyEvent("you are too young to do this"));
intChild.Print();
}
}
public abstract class BaseCompanyEvent
{
protected string Value { get; private set; }
public BaseCompanyEvent(string value)
{
Value = value;
}
public abstract string GetMessage();
}
public class FirstCompanyEvent : BaseCompanyEvent
{
public FirstCompanyEvent(string value)
: base(value)
{ }
public override string GetMessage()
{
return "First born: " + Value;
}
}
public class SecondCompanyEvent : BaseCompanyEvent
{
public SecondCompanyEvent(string value)
: base(value)
{ }
public override string GetMessage()
{
return "Younger brother: " + Value;
}
}
public abstract class Mother<T> where T : BaseCompanyEvent
{
protected T CustomEvent { get; private set; }
public Mother(T customEvent)
{
CustomEvent = customEvent;
}
public abstract void Print();
}
public class FirstChild : Mother<FirstCompanyEvent>
{
public FirstChild(FirstCompanyEvent e)
: base(e)
{ }
public override void Print()
{
Console.WriteLine(CustomEvent.GetMessage());
}
}
public class SecondChild : Mother<SecondCompanyEvent>
{
public SecondChild(SecondCompanyEvent e)
: base(e)
{ }
public override void Print()
{
Console.WriteLine(CustomEvent.GetMessage());
}
}
}
I'm trying to create instance of class Bar but I'm receiving an error:
"Cannot implicitly convert type ConsoleApplication1.Bar to
ConsoleApplication1.BaseFoo<ConsoleApplication1.baseOutput,
ConsoleApplication1.baseInput>"
Any idea what I'm missing or what I'm doing wrong? Any advice will be nice.
public class baseOutput
{
public string output;
}
public class baseInput
{
public string input;
}
public class ExtendOutput : baseOutput
{
public long id;
}
public class ExtendInput : baseInput
{
public long id;
}
public class BaseFoo<baseOutput, baseInput>
{
protected virtual void DoSmth()
{
}
}
public class Bar : BaseFoo<ExtendOutput, ExtendInput>
{
protected override void DoSmth()
{
base.DoSmth();
}
}
public class Test
{
public void Show()
{
}
private BaseFoo<baseOutput, baseInput> CreateInstance()
{
return new Bar(); // Error right here
}
}
I'll give you an example of why you're prevented from doing that.
Imagine instead, your classes were written like this:
public class BaseFoo<TOutput, TInput>
where TOutput : BaseOutput
{
public TOutput Something { get; set; }
}
public class Bar : BaseFoo<ExtendOutput, ExtendInput>
{
}
public class BaseInput { }
public class BaseOutput { }
public class ExtendOutput : BaseOutput { }
public class SomethingElse : BaseOutput { }
Now, you have this method:
private BaseFoo<BaseOutput, BaseInput> CreateInstance()
{
//At this point, Something will be of type ExtendOutput.
return new Bar();
}
So, we call it like this:
var myBar = CreateInstance();
Now, mybar.Something is of type BaseOutput. That's fine, though, because ExtendOutput : BaseOutput, right? Not quite.
What happens when we do this:
myBar.Something = new SomethingElse();
That's valid, because Something expects a BaseOutput, and SomethingElse is a BaseOutput. However, the object is actually a Bar, which explicitly says it should be an ExtendOutput.
The problem is clearer if we attempt to cast it back:
var myBaseFoo = CreateInstance();
myBaseFoo.Something = new SomethingElse();
Bar myBar = (Bar)myBaseFoo;
myBar.Something; // Here, we're told it's going to be an `ExtendOutput`,
// but we get a `SomethingElse`?
That's clearly wrong. And that's why you're prevented from doing what you're trying to do. You can have this behavior with covariance.
Covariance makes it illegal to pass in a TOutput. So, this line
public TOutput Something { get; set; }
Would be invalid. We would only be allowed to expose the getter:
public TOutput Something { get; }
Which alleviates the above problem
Bar is BaseFoo<ExtendOutput, ExtendInput>, and CreateInstance() requires BaseFoo<baseOutput, baseInput> to be returned, so it can't return Bar which is BaseFoo<ExtendOutput, ExtendInput>.
Regardless ExtendOutput inherits baseOutput, when you inherit a generic class the inheritance is invariant.
Consider using interfaces with in and out generic modifiers:
public class baseOutput
{
public string output;
}
public class baseInput
{
public string input;
}
public class ExtendOutput : baseOutput
{
public long id;
}
public class ExtendInput : baseInput
{
public long id;
}
public interface IBaseFoo<out T1, out T2>
{
public void DoSmth();
}
public class Bar : IBaseFoo<ExtendOutput, ExtendInput>
{
public void DoSmth()
{
}
}
public class Test
{
public void Show()
{
}
private IBaseFoo<baseOutput, baseInput> CreateInstance()
{
return new Bar();
}
}
Is there any nice, elegant way to get properties from generic type used in abstract superclass without using interfaces?
Here's an example:
public abstract class CoolBase<T>
where T : class
{
private IEnumerable<T> somEnumerable;
public void GetPersonProperties()
{
var name = somEnumerable.First().Name; //this doesn't work
}
}
public class CoolA : CoolBase<Person>
{
}
public class Person
{
public string Name { get; set; }
public string Region { get; set; }
}
}
The goal of using generic classes is type-flexibility -
therefore it makes no sence to declare a method in a generic class which
uses Person-specific methods.
You should implement such detailed methods in the concrete implementations of
your abstract, generic class (here CoolA).
Maybe it is helpful for you to declare an abstract method getProperties()
int the generic, abstract class, wich can be implemented in CoolA via using
Person-specific code.
public abstract class CoolBase<T>
where T : class
{
private IEnumerable<T> somEnumerable;
public abstract void getProperties();
}
public class CoolA : CoolBase<Person>
{
public override void getProperties()
{
//should work, somEnumberable is made of Persons here
var name = somEnumerable.First().Name;
}
}
It makes no sense to put GetPersonProperties in CoolBase. CoolBase is generic, so should not have a class-specific functionality within it.
You could create a abstract method in CoolBase and implement it in your derived type:
public abstract class CoolBase<T> where T : class
{
protected IEnumerable<T> somEnumerable;
public abstract void GetProperties();
}
public class CoolA : CoolBase<Person>
{
public override void GetProperties()
{
var name = somEnumerable.First().Name;
}
}
public class Person
{
public string Name { get; set; }
public string Region { get; set; }
}
Alternatively, you could you reflection to get at the properties of T at runtime:
public abstract class CoolBase<T> where T : class
{
private IEnumerable<T> somEnumerable;
public void GetProperties()
{
foreach (var prop in typeof (T).GetProperties())
{
// do something with each property
}
}
}
A noob question...
I've got two classes, a common(parent) one and a specialized(child)one :
public abstract class BaseTest
{
public BaseTestSettings Settings{get;set;}
public abstract void Run();
}
public class BaseTestSettings
{
public double SettingsProp1{get;set;}
public double SettingsProp1{get;set;}
}
public class SpecializaedTestSettings : BaseTestSettings
{
public double SpecializaedTestSettingsPropA{get;set;}
public double SpecializaedTestSettingsPropB{get;set;}
}
public class SpecializaedTest : BaseTest
{
public SpecializaedTest()
{
this.Settings = new SpecializaedTestSettings();
}
public override void Run()
{
SpecializaedTestSettings settings = (SpecializaedTestSettings)this.Settings;
}
}
Is there a way to avoid casting in the overridden Run method in the specialized test ? I guess a solution would be to define a Settings property of type SpecializedTestSettings in the SpecializedTest class, but my goal is to avoid to this and declare those properties only once. I guess I can't ?
Use Generics :
public abstract class BaseTest<TSettings> where TSettings : BaseTestSettings
{
public TSettings Settings{get;set;}
public abstract void Run();
}
public class BaseTestSettings
{
public double SettingsProp1{get;set;}
public double SettingsProp1{get;set;}
}
public class SpecializaedTestSettings : BaseTestSettings
{
public double SpecializaedTestSettingsPropA{get;set;}
public double SpecializaedTestSettingsPropB{get;set;}
}
public class SpecializaedTest : BaseTest<SpecializaedTestSettings>
{
public SpecializaedTest()
{
this.Settings = new SpecializaedTestSettings();
}
public override void Run()
{
SpecializaedTestSettings settings = this.Settings;
}
}
If you need a non generic/covariant version you can write a covariant interface or a non generic base type.
I want to create a class that could hold any of a number of same type of classes. For example lets says I have a base class like follows:
public class BaseClass
{
public string MyBaseString
{
get;
set;
}
}
And then I have a few derived classes like this:
public class DerivedClass : BaseClass
{
public MyDerivedClassString
{
get;
set;
}
}
public class DerivedClass2 : BaseClass
{
public MyDerivedClass2String
{
get;
set;
}
}
Now I would like a class that accepts one of these implementations and does stuff with it. Here is the only thing I can think of, but there must be a better way:
public class ClassA
{
public object MyClass
{
get;
set;
}
public ClassA (object myClass)
{
MyClass = myClass;
if (object is BaseClass)
{
//do something
}
else if (object is DerivedClass)
{
//do something specific to derived class
}
else if (object is DerivedClass2)
{
//do something specific to derived class 2
}
}
}
CLARIFICATION: The specific goal I am trying to accomplish is to use ClassA as a container class for various implementations of the BaseClass. The business goal I am trying to accomplish is to create a Legend object which might use multiple color schemes (i.e. a Mono Color Ramp, Multi Color Ramp, etc). So I would like the Legend class to contain the ColorScheme that is being used, but still have access to that color scheme's unique properties for modification later on.
CLARIFICATION 2 Based on the wide array of responses I got, I thought I'd provide an exact replication of what I'm trying to do:
public class BaseColorScheme
{
List<Color> _colors = new List<Color>();
public List<Color> Colors
{
get
{
return _colors;
}
set
{
_colors = value;
}
}
}
public class SingleColorScheme : BaseColorScheme
{
public Color MidColor
{
get;
set;
}
public SingleColorScheme( Color midColor, int numberOfClassifications )
{
Colors = CreateMonoColorRamp( midColor, numberOfClassifications );
}
}
public class MultiColorScheme : BaseColorScheme
{
public Color StartColor
{
get;
set;
}
public Color EndColor
{
get;
set;
}
public Color MidColor
{
get;
set;
}
public MultiColorScheme( Color startColor, Color endColor, Color midColor )
{
StartColor = startColor;
EndColor = endColor;
MidColor = midColor;
Colors = //do something to define multi color scheme
}
}
Then I would have a Legend Class that would be something like
public class Legend
{
public object ColorScheme
{ get; set; }
public Guid LegendId
{ get; set; }
public Legend(object colorScheme)
{
ColorScheme = colorScheme;
}
}
Finally I might have a form that sits on top of the legend that displays the properties of the various color schemes based on which type of color scheme it is. Hopefully that helps clarify a bit.
public class ClassA<T> where T : BaseClass
{
public T MyClass { get; set; }
public ClassA(T myClass) { MyClass = myClass; }
}
Beyond that, define the common interface of the class hierarchy either as an interface or as methods (concrete, abstract, or virtual) within the base class. Then you can be assured all derived classes have such method / properties and can use them within your generic wrapper.
Instead of letting ClassA perform whatever needs to be done, you can use polymorphism and let the classes do it to themselves.
Simply declare a virtual method in the base class, have it do whatever you need it do so, and then override this method in the subclasses. In the method in ClassA, you just need to call that method on the object you receive as a parameter - without having to care about the specific type.
If you need to access different properties based on which derived class is passed something like this should help:
public class ClassA<T> where T : BaseClass
{
public T MyClass { get; set; }
public ClassA(T myClass) { MyClass = myClass; }
public void DoStuffToMyClass()
{
if(MyClass is BaseClass)
{ // do base class stuff }
else if(Myclass is DerivedClass)
{ // do DerivedClass stuff }
else if(MyClass is DerivedClass2)
{ // do DerivedClass2 stuff }
}
}
This gives you the type saftey to ensure you at least have the BaseClass object, and possibly a derived class.
The answer is polymorphism, let the object do it themselves.
public class BaseClass
{
public string MyString { get; set; }
public virtual string DoIt()
{
return "I'm Base Class";
}
}
public class DerivedClassA
{
public override string DoIt()
{
return "I'm Derived Class A";
}
}
public class DerivedClassB
{
public override string DoIt()
{
return "I'm Derived Class B";
}
}
....
public ClassA (BaseClass myClass)
{
MyClass = myClass;
MyClass.DoIt();
}
.....
ClassA x1 = ClassA(new BaseClass()) // calls BaseClass.DoIt()
ClassA x2 = ClassA(new DerivedClassA()) // calls DerivedClassA.DoIt()
ClassA x3 = ClassA(new DerivedClassB()) // calls DerivedClassB.DoIt()
whenever you catch yourself acting differently based on the run-time type of the object, you are dealing with code that breaks OO principles, i.e. a class that does not respect the base class contract.
Can you use virtual methods?
public abstract class BaseClass
{
public abstract void DoStuff();
}
public class DerivedClass1 : BaseClass
{
public override void DoStuff()
{
...
}
}
public class DerivedClass2 : BaseClass
{
public override void DoStuff()
{
...
}
}
Without generics:
public class ClassA
{
public BaseClass MyClass
{
get;
set;
}
public ClassA (BaseClass myClass)
{
MyClass = myClass;
myClass.DoStuff();
}
}
or with generics:
public class ClassA<T> where T : BaseClass
{
public T MyClass { get; set; }
public ClassA (T myClass)
{
MyClass = myClass;
myClass.DoStuff();
}
}
Keep it simple: polymorphism
Hopefully your objects have a common interface, something like:
class Base {
public virtual void DoSomething() { /* Default implementation */ }
}
class Derived1 : Base {
public override void DoSomething() { /* Implementation specific to this type */ }
}
class Derived2 : Base {
public override void DoSomething() { /* Another implementation specific to this type */ }
}
Or maybe they implement a common interface. So hopefully your consuming class can hold the most general representation of your inputs as possible and invoke code as such:
class Dependent {
public Dependent(Base instance) {
instance.DoSomething();
}
}
So your Dependent class doesn't really are whether it has a derived type or a base type.
Not quite as simple: visitor pattern
Sometimes polymorphism doesn't really work, which is particularly the case if you need to access the specific members of your derived classes, and those members aren't in the base class. Visitor pattern works well in this case, especially if you have a fixed, well-defined graph of objects.
public interface IVisitor<T> {
T Visit(Base x);
T Visit(Derived1 x);
T Visit(Derived2 x);
}
class Base {
public virtual T Accept<T>(IVisitor<T> visitor) { visitor.Visit(this); }
public string BaseString { get; set; }
}
class Derived1 : Base {
public override T Accept<T>(IVisitor<T> visitor) { visitor.Visit(this); }
public string Derived1String { get; set; }
}
class Derived2 : Base {
public override T Accept<T>(IVisitor<T> visitor) { visitor.Visit(this); }
public string Derived2String { get; set; }
}
So Derived1 and Derived2 have a different set of properties, and if you need to get to those properties without a runtime type-checking, implement a visitor:
class DefaultStringVisitor : IBaseVisitor<string> {
public string Visit(Base x) { return x.BaseString; }
public string Visit(Derived1 x) { return x.Derived1String; }
public string Visit(Derived2 x) { return x.Derived2String; }
}
class Dependent {
public Dependent(Base x) {
string whatever = x.Accept<string>(new DefaultStringVisitor());
}
}
So the visitor pattern gives you access to your derived object's members without a type-check. Its a somewhat inflexible pattern (i.e. need to know which objects to visit up front), but it might work for your needs.