Appropriate design / design pattern for this problem?

I previously posted this one , but I think it was too verbose and inappropriate. My question is also similar to this . One poster in the second link said that the answer (why can't you make the code below) was a design issue, in particular the “poor use of inheritance”. Therefore, I would like to check this problem again with the experts at StackOverflow and see if this is really a bad inheritance problem, but more importantly, how to fix the design.

Like the poster, I am also confused about the Factory method and how I can apply it. It seems the Factory method is intended for several specific classes that have the same implementation as the abstract base class and do not add their own properties . But, as you will see below, my specific classes are based on an abstract base class and add additional properties .

The base class that we will build on:

public abstract class FlatScreenTV { public string Size { get; set; } public string ScreenType { get; set; } } 

Examples of extension classes:

 public class PhillipsFlatScreenTV : FlatScreenTV { // Specific to Phillips TVs. Controls the backlight intensity of the LCD screen. public double BackLightIntensity { get; set; } } public class SamsungFlatScreenTV : FlatScreenTV { // Specific to Samsung TVs. Controls the time until the TV automatically turns off. public int AutoShutdownTime { get; set; } } 

Suppose there are more extension classes for more flat screen TVs. And then, let's say we insert them all into a general list:

 public static void Main() { List<FlatScreenTV> tvList = new List<FlatScreenTV>(); tvList.Add(new PhillipsFlatScreenTV()); tvList.Add(new SamsungFlatScreenTV()); tvList.Add(new SharpFlatScreenTV()); tvList.Add(new VizioFlatScreenTV()); FlatScreenTV tv = tvList[9]; // Randomly get one TV out of our huge list } 

Problem:

I want to access the specific properties of any "original" brand to which this variable belongs. I know the brand because if I call tv.GetType() , it returns the correct "original" type - not FlatScreenTV . But I need to be able to tv from FlatScreenTV to return to the original type in order to be able to access the specific properties of each brand of flat-screen TVs.

Question No. 1: How can I dynamically cast this, correctly - without temporary hacks and huge if-else chains, to roughly guess the type of "original"?

After looking at similar design problems, most of the answers are: you cannot . Some people say to look at the Factory template, while others say that you need to revise the design using interfaces, but I don’t know how to use either to solve this problem.

Question # 2: So, how do I create these classes so that I can access the original properties of the type in the context above?

Question # 3: Is this really bad inheritance?

+4
source share
5 answers

Your design violates the Liskov Replacement Principle . In other words, the code that refers to the items from your FlatScreenTV list should not know and not care about which derived type.

Say that your code needs to create a custom remote control GUI. Simply find out the names and types of properties of each TV to automatically create a user interface. In this case, you can do something similar to set custom properties from the base class:

 public abstract class FlatScreenTV { public FlatScreenTV() { CustomProperties = new Dictionary<string,object>(); } public Dictionary<string,object> 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 need to work directly with derived types, you should instead switch to a plug-in architecture. For example, you may have a factory method, for example:

 IRemoteControlGUI GetRemoteControlGUIFor(FlatScreenTV tv) 

which will scan your plugins and find one that knew how to create a user interface for the specific type of FlatScreenTV that you transferred. This means that for every new FlatScreenTV added, you also need to create a plugin that knows how to make your remote control GUI.

+5
source

Factory Sample will be the best way

+1
source

I can offer a partial answer:

First I read about the principle of Liskov substitution.

Secondly, you create objects that inherit from FlatScreenTV, but apparently in no way, since you want to refer to them with your SubType (SpecificTVType), and not their SuperType (FlatScreenTV). This is a bad use of Inheritance, as it does NOT use lol inheritance.

If your code wants to access properties specific to this type, then you really want this code to be encapsulated in this type. Otherwise, every time you add a new type of TV, all the code that processes the TV list must be updated to reflect this.

So, you have to turn on the FlatScreenTV method, which makes x, and override it on the TV as needed.

So, basically in your main method above, instead of thinking that I want to deal with TVTypeX, you should always refer to the base type, and let the inheritance and method override the handling of specific behavior for the subtype you are really dealing with .

Code, for example.

  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 } } 
+1
source

"The factory method is intended for several specific classes that have the same implementation as the abstract base class [interface] and do not add their own properties."

No, speaking more practical than theoretically, the factory method can provide you with objects of specific classes in which specific classes should 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 call it, and I need to call it several times, and sometimes I use a method that creates several different class objects, and maybe it confuses, maybe be another question

And your further comment on the suggestion of switching with many options when using the factory template usually provides the identifier of a particular class / specific object. This can be a string, an integer, an identifier of a special type, or an enumerated type.

Instead, you can use the integer / enum identifier and use the collection to search for a particular class.

0
source

You can still use factory. The point in the factory IMO is to put all the heavy lifting design of your TVs in one place. Say categorically "a factory for several specific classes that have the same implementation as the abstract base class", forgets about polymorphism.

There is no law stating that you cannot use the factory pattern because subclasses declare unique properties and methods. But the more you can use polymorphism, the more important the a factory pattern is. In addition, as a general IMHO guide, the harder it is to build from the base, the better than what you end up using with the factory, because you are “encapsulating changes”, that is, building specific classes is most likely a change due to different requirements and the inherent complexity of the design (of course, a solution for computational analysis). And this change is in one class - factory.

Try the following: Define everything in an abstract class, and then for a given subclass of TV, either write a specific code, and for those that are not applicable, write the standard code "I do not do this."

Think about all the things your TVs do in general terms: turn it on, turn it off, etc. Write the shell of the virtual method in the base class for all the common things that TV does - this is a simple example of a sample template method by the way. Then redefine them in specific classes as needed.

There are other things that you can do in the base class to make it more fundamental (that the technical term means "reference subclasses as a base class, but does sub-cool things").

  • Define delegate methods (very powerful, but underused)
  • use parameters [] for parameter lists of dynamic methods
  • Make Property Delegates
  • Static methods
  • Declare properties and methods "abstract" - forcibly implements the implementation of the subclass, vis-a-vis "virtual"
  • Hide inherited things in a subclass (usually using the keyword “new” to specifically report this)
  • If the design parameters are numerous or complex, create a class specifically designed to pass the configuration to the factory assembly method.



  public class TVFactory { public TV BuildTV(Brands thisKind) { TV newSet; switch (thisKind) { case Brands.Samsung : Samsung aSamsungTV = new Samsung(); aSamsungTV.BacklightIntensity = double.MinVal; aSamsungTV.AutoShutdownTime = 45; //oops! I made a magic number. My bad aSamsungTV.SetAutoShutDownTime = new delegate (newSet.SetASDT); newSet = aSamsungTV; break; . . . } // switch } //more build methods for setting specific parameters public TV BuildTV (Brands thisKind, string Size) { ... } // maybe you can pass in a set of properties to exactly control the construction. // returning a concrete class reference violates the spirit of object oriented programming public Sony BuildSonyTV (...) {} public TV BuildTV (Brands thisKind, Dictionary buildParameters) { ... } } public class TV { public string Size { get; set; } public string ScreenType { get; set; } public double BackLightIntensity { get; set; } public int AutoShutdownTime { get; set; } //define delegates to get/set properties public delegate int GetAutoShutDownTime (); public delegate void SetAutoShutDownTime (object obj); public virtual TurnOn (); public virtural TurnOff(); // this method implemented by more than one concrete class, so I use that // as an excuse to declare it in my base. public virtual SomeSonyPhillipsOnlything () { throw new NotImplementedException("I don't do SonyPhillips stuff"); } } public class Samsung : TV { public Samsung() { // set the properties, delegates, etc. in the factory // that way if we ever get new properties we don't open umpteen TV concrete classes // to add it. We're only altering the TVFactory. // This demonstrates how a factory isolates code changes for object construction. } public override void TurnOn() { // do stuff } public override void TurnOn() { // do stuff } public void SamsungUniqueThing () { // do samsung unique stuff } internal void SetASDT (int i) { AutoShutDownTime = i; } } // I like enumerations. // No worries about string gotchas // we get intellense in Visual Studio // has a documentation-y quality enum Brands { Sony ,Samsung ,Phillips } 
0
source

All Articles