如果以前曾提出过类似的问题,我会提前道歉,正确描述我要找的内容非常复杂,我会用一个例子来解释。
我们将使用名为Shape
的基类和以下子类:Triangle
,Square
,Pentagon
和Hexagon
。最后4个类分别代表具有3,4,5和6个边的形状。这些信息属于"到类本身而不是那些类的实例。
我们还假设每个类都有一个返回给定颜色的静态方法。给定类的每个实例都将共享相同的颜色。
我想要做的是按照其边数的升序调用我的形状的静态函数getColor()
。意思是,我想打电话:
Triangle.getColor()
Square.getColor()
Pentagon.getColor()
Hexagon.getColor()
不幸的是,我遇到了以下问题(由许多编程语言共享)
我无法使用接口,因为这些信息不属于实例,而是属于类
我无法在getSideCount()
课程中定义Shape
静态函数,因为我无法"覆盖"它在我的孩子课程中获得正确数量的边
我不是要求完整的代码,只是为了设计建议来管理这个问题。也许我完全错了,我不应该这样做。不要犹豫,批评并建议一种新方法来做到这一点。
如果你想要一个更具体的"具体的"例如:
我有一个字符串myString
。
我有多个类A
,B
,C
定义toString
方法。
a.toString()
返回1个字符的字符串b.toString()
返回2个字符的字符串c.toString()
返回3个字符的字符串 myString
是a.toString()
,b.toString()
和c.toString()
:ABBCCC
的串联。
明天,我可能希望myString
是c.toString()
,a.toString()
和b.toString()
:CCCABB
的串联。因此,我在类A
,B
和C
中定义了一个静态方法,返回myString
中实例表示的位置。我想要做的是以正确的顺序提取我的实例的表示。
" long"这样做的方法是:
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
提前感谢您的时间和帮助。
答案 0 :(得分:2)
有几种方法可以解决这个问题。
如果你的语言支持它(Scala,F#,Haskell),可能最简单的就是模式匹配。通过支持(exchaustive)模式匹配,您可以区分对象类型:
// 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
...
}
这有效地将getColor
方法移到了课堂之外,但是你用一个普通的" switch-case"来获得很酷的东西。如果你没有涵盖所有的情况,编译器会警告你,所以你有效地得到与抽象方法相同的编译时保证。
一般来说,您需要的是映射从类型到值的方法,所以您也可以只需使用地图。在C#中,您将使用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()];
这可以让您获得更大的灵活性,但您很容易忘记为新添加的类型注册颜色。此外,您可能会为每种颜色注册一个ShapeInfo
课程,而不只是Color
,这样您就不会有多个词典。
另一种选择(同样是C#示例,对不起,如果您正在使用Java)实际上是将实例方法与之前的想法(静态字典)和一些结合起来反射即可。这个想法就像是:
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();
}
}
但是现在您已使用toString
内容更新了问题,我不再确定您的实际目标是什么。 :)
答案 1 :(得分:0)
我可能会误解,但我会在shape类中有一个抽象方法,它在每个子类中被重写。然后,使用对象数组,可以根据sideNumber()方法返回的值对它们进行排序。然后只需遍历排序的数组,在每个数组上调用get颜色。