Your design violates the Liskov Substitution Principle In other words, the code that deals with items from your list of FlatScreenTV shouldn't know or care what derived type is Say your code needs to create a custom remote control GUI. It might be enough to simply know the names and types of the properties of each TV to auto-generate the UI. In which case you could do something like this to expose the custom properties from the base class: public abstract class FlatScreenTV { public FlatScreenTV() { CustomProperties = new Dictionary(); } public Dictionary CustomProperties { get; private set; } public string Size { get; set; } public string ScreenType { get; set; } } public class PhillipsFlatScreenTV : FlatScreenTV { public PhillipsFlatScreenTV() { BackLightIntensity = 0; } // Specific to Phillips TVs.
Controls the backlight intensity of the LCD screen. Public double BackLightIntensity { get { return (double)CustomProperties"BackLightIntensity"; } set { CustomProperties"BackLightIntensity" = value; } } } public class SamsungFlatScreenTV : FlatScreenTV { public SamsungFlatScreenTV() { AutoShutdownTime = 0; } // Specific to Samsung TVs. Controls the time until the TV automatically turns off.
Public int AutoShutdownTime { get { return (int)CustomProperties"AutoShutdownTime"; } set { CustomProperties"AutoShutdownTime" = value; } } } If you really do need to be working directly with the derived types, then you should instead consider moving to a plugin based architecture. For example, you might have a factory method like this: IRemoteControlGUI GetRemoteControlGUIFor(FlatScreenTV tv) which would scan your plugins and find the one that knew how to build the UI for the particular type of FlatScreenTV you passed in. This means that for every new FlatScreenTV you add, you also need to create a plugin that knows how to make its remote control GUI.
Your design violates the "Liskov Substitution Principle". In other words, the code that deals with items from your list of FlatScreenTV shouldn't know or care what derived type is. Say your code needs to create a custom remote control GUI.It might be enough to simply know the names and types of the properties of each TV to auto-generate the UI.
In which case you could do something like this to expose the custom properties from the base class: public abstract class FlatScreenTV { public FlatScreenTV() { CustomProperties = new Dictionary(); } public Dictionary CustomProperties { get; private set; } public string Size { get; set; } public string ScreenType { get; set; } } public class PhillipsFlatScreenTV : FlatScreenTV { public PhillipsFlatScreenTV() { BackLightIntensity = 0; } // Specific to Phillips TVs. Controls the backlight intensity of the LCD screen. Public double BackLightIntensity { get { return (double)CustomProperties"BackLightIntensity"; } set { CustomProperties"BackLightIntensity" = value; } } } public class SamsungFlatScreenTV : FlatScreenTV { public SamsungFlatScreenTV() { AutoShutdownTime = 0; } // Specific to Samsung TVs.
Controls the time until the TV automatically turns off. Public int AutoShutdownTime { get { return (int)CustomProperties"AutoShutdownTime"; } set { CustomProperties"AutoShutdownTime" = value; } } } If you really do need to be working directly with the derived types, then you should instead consider moving to a plugin based architecture. For example, you might have a factory method like this: IRemoteControlGUI GetRemoteControlGUIFor(FlatScreenTV tv) which would scan your plugins and find the one that knew how to build the UI for the particular type of FlatScreenTV you passed in.
This means that for every new FlatScreenTV you add, you also need to create a plugin that knows how to make its remote control GUI.
Factory Pattern would be the best way to go.
As I said in my post, the Factory Design Pattern implementation only seems to be compatible when the bunch of concrete classes follow the EXACT implementation of the abstract class and do NOT add their own extra properties. Mine do. – Jason Jun 30 at 9:26 FlatScreenTV tv = tvList9; if(tv.GetType() == typeof(SamsungFlatScreenTV)) { (tv as SamsungFlatScreenTV).
AutoShutdownTime = 100; }. What is wrong with doing something like that? – harryovers Jun 30 at 9:30 Because I also said I didn't want a huge if-else ladder 'brute-guessing' the original type.
There must be a better design to naturally return the appropriate type. If I need to do this more than once I'm not going to if-else all 100 different type am I? – Jason Jun 30 at 9:31 a simple switch statement would be better than a load of ifs & elses – harryovers Jun 30 at 9:35 Yeah but these solutions don't resolve the design issue.
If-else/switch same difference in the context of trying to solve the design issue, and not just applying a temporary patch. – Jason Jun 30 at 9:35.
I can offer a partial answer: Firstly read up on Liskov's Substitution Principle. Secondly you are creating objects that inherit from FlatScreenTV, but apparently for no purpose as you want to refer to them by their SubType (SpecificTVType) and not their SuperType (FlatScreenTV) - This is bad use of Inheritance as it is NOT using inheritance lol. If your code wants to access properties particular to a given type, then you really want this code encapsulated within that type.
Otherwise everytime you add a new TV type, all the code that handles the TV list would need to be updated to reflect that. So you should include a method on FlatScreenTV that does x, and override this in TV's as required. So basically in your Main method above, instead of thinking I want to be dealing with TVTypeX, you should always refer to the basetype, and let inheritance and method overriding handle the specific behaviour for the subtype you are actually dealing with.
Code eg. Public abstract class FlatScreenTV { public virtual void SetOptimumDisplay() { //do nothing - base class has no implementation here } } public class PhilipsWD20TV { public int BackLightIntensity {get;set;} public override void SetOptimumDisplay() { //Do Something that uses BackLightIntensity } }.
Thanks that's definitely a new direction and approach. Only thing that seems to come to mind with this though....if I had tens of properties in my base class, and my overriding classes don't use most of them, wouldn't that be extremely verbose to leave empty override methods (even though I have to)? But I guess this is the "proper" way to do it?
– Jason Jun 30 at 9:35 but if he has a collection List tvList = new List(); then he would still need to cast the object. – harryovers Jun 30 at 9:40 Umm - without seeing more code difficult to comment, but I would say localise properties to the types which need them. If it makes sense for your application to set a property value, then it needs to be in the base type.
If instead you can provide a method which sets different properties on different TVTypes, then just implement that method in the base, and the specific properties it needs along with the specific overridden method in the subtype. – BonyT Jun 30 at 9:41 @harry - no he wouldn't - that's the whole benefit of this approach. – BonyT Jun 30 at 9:42 how do you propose putting instances of the different types into a single collection then?
– harryovers Jun 30 at 9:43.
The factory method is for multiple concrete classes that have the exact same implementation as the abstract base class interface and do not add their own properties. " No, speaking more practical, than theorical, the factory method can provide you with objects of concrete classes, in which the concrete classes, must have some common methods and interfaces, but, also some additional specific attributes. Sometimes I use a method that creates the same class object every time I called, and I need to call it several times, and sometimes I use a method that create several different class objects, and that maybe be confusing, maybe another question.
And, your further comment about a switch sentence, with many options, when using the factory pattern, you usually provide an identifier for the concrete class / concrete object. This can be a string, an integer, an special type id, or an enumerated type. You could use an integer / enum ID instead, and use a collection to lookup for the concrete class.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.