I apologize in advance if a similar question has been asked before, it's quite complicated to describe correctly what I am looking for, and I will use an example to explain.
We will work with a base class named Shape with the following child classes : Triangle, Square, Pentagon and Hexagon. The 4 last classes represent a shape with 3, 4, 5 and 6 sides respectively. This information "belongs" to the class itself and not to the instance of those classes.
We will also suppose that each class has a static method returning a given color. Every instance of a given class will share the same color.
What I want to do is to call the static function getColor() of my shapes in the ascending order of their number of sides. Meaning, I want to call :
Triangle.getColor() Square.getColor() Pentagon.getColor() Hexagon.getColor() Unfortunately, I have the following problems (shared by many programming languages)
I can't use Interfaces because the information does not belong to the instances but the classes
I can't define the getSideCount() static function inside my Shape class because I would not be able to "override" it in my child classes to get the correct number of sides

I am not asking for a complete code, only for design advices to manage this problem. Maybe I am totally wrong and I should not go this way. Don't hesitate to criticize and suggest a new way to do this.
If you want a more "concrete" example :
I have a string myString.
I have multiple classes A, B, C defining the toString method.
a.toString() returns a string of 1 characterb.toString() returns a string of 2 charactersc.toString() returns a string of 3 charactersmyString is the concatenation of a.toString(), b.toString() and c.toString() : ABBCCC.
Tomorrow, I may want that myString is the concatenation of c.toString(), a.toString() and b.toString() : CCCABB. Thus, I defined a static method in the classes A, B and C returning the position of the representation of the instance in myString. What I want to do is to extract in the correct order the representation of my instances.
The "long" way to do this would be :
index ← 0
if( A.position == 1 )
aStr ← extract( myString, index, 1 )
index ← index + 1
elif ( B.position == 1 )
bStr ← extract( myString, index, 2 )
index ← index + 2
elif ( C.position == 1 )
cStr ← extract( myString, index, 3 )
index ← index + 3
endif
if( A.position == 2 )
aStr ← extract( myString, index, 1 )
index ← index + 1
elif ( B.position == 2 )
bStr ← extract( myString, index, 2 )
index ← index + 2
elif ( C.position == 2 )
cStr ← extract( myString, index, 3 )
index ← index + 3
endif
if( A.position == 3 )
aStr ← extract( myString, index, 1 )
index ← index + 1
elif ( B.position == 3 )
bStr ← extract( myString, index, 2 )
index ← index + 2
elif ( C.position == 3 )
cStr ← extract( myString, index, 3 )
index ← index + 3
endif
Thank you in advance for your time and your help.
There are several ways you can approach this.
Probably the simplest one would be pattern matching, if your language supports it (Scala, F#, Haskell). With support for (exchaustive) pattern matching, you would differentiate on the object type:
// syntax will differ from language to language,
// but you should get the idea
def getColor(s: Shape): Color = s match {
case Triangle => Color.Blue
case Square => Color.Yellow
...
}
This effectively moves the getColor method outside of the class, but the cool thing that you won't get with a plain "switch-case" is that compiler will warn you if you don't cover all the cases, so you effectively get the same compile-time guarantee as with abstract methods.
In general, what you need is a way to map from a type to a value, so you might as well simply use a map. In C#, you would use a Dictionary<Key, Value>:
static readonly Dictionary<Type, Color> _shapeToColor;
// use this to register a color for each type somewhere at the beginning
public static Register<T>(Color color) where T : Shape
{
_shapeToColor[typeof(T)] = color;
}
// generic version for compile-time read
public static Color GetColor<T>() where T : Shape => _shapeToColor[typeof(T)];
// or a parameterized version for run-time read
// (but might fail if incorrect type passed)
public static Color GetColor(Type t) => _shapeToColor[t];
// or generally
public static Color GetColor(object x) => _shapeToColor[x.GetType()];
This is allows you greater flexibility, but you can easily forget to register a color for a newly added type. Also, you would probably register a ShapeInfo class for each color, and put there more than just a Color, so that you don't have several dictionaries.
Another option (again a C# example, sorry if you're using Java) is to actually combine instance methods with the previous idea (static dictionary) and some reflection. The idea would then be something like:
interface IShape
{
Color GetColor();
}
class Triangle : IShape
{
public Color GetColor() => Color.Blue;
}
class Square : IShape
{
public Color GetColor() => Color.Red;
}
static void InitializeValues()
{
// use reflection to iterate through all types
var asm = Assembly.GetAssembly(typeof(IShape));
foreach (var t in asm.GetTypes())
{
// find all Shapes
if (t.IsInterface ||
t.IsAbstract ||
!typeof(IConfigTokenizer).IsAssignableFrom(t))
continue;
// instantiate a temporary shape
var inst = (IShape)Activator.CreateInstance(t);
// but we are only interested in creating
// a mapping to the result of GetColor
_shapeToColor[t] = inst.GetColor();
}
}
But now that you've updated the question with that toString stuff, I am no longer sure what your actual goal is. :)
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