使用子类

时间:2017-03-20 17:46:17

标签: oop inheritance static

如果以前曾提出过类似的问题,我会提前道歉,正确描述我要找的内容非常复杂,我会用一个例子来解释。

我们将使用名为Shape的基类和以下子类:TriangleSquarePentagonHexagon。最后4个类分别代表具有3,4,5和6个边的形状。这些信息属于"到类本身而不是那些类的实例。

我们还假设每个类都有一个返回给定颜色的静态方法。给定类的每个实例都将共享相同的颜色。

我想要做的是按照其边数的升序调用我的形状的静态函数getColor()。意思是,我想打电话:

  1. Triangle.getColor()
  2. Square.getColor()
  3. Pentagon.getColor()
  4. Hexagon.getColor()
  5. 不幸的是,我遇到了以下问题(由许多编程语言共享)

    • 我无法使用接口,因为这些信息不属于实例,而是属于类

    • 我无法在getSideCount()课程中定义Shape静态函数,因为我无法"覆盖"它在我的孩子课程中获得正确数量的边

    child classes

    我不是要求完整的代码,只是为了设计建议来管理这个问题。也许我完全错了,我不应该这样做。不要犹豫,批评并建议一种新方法来做到这一点。

    如果你想要一个更具体的"具体的"例如:

    我有一个字符串myString

    我有多个类ABC定义toString方法。

    • a.toString()返回1个字符的字符串
    • b.toString()返回2个字符的字符串
    • c.toString()返回3个字符的字符串

    myStringa.toString()b.toString()c.toString()ABBCCC的串联。

    明天,我可能希望myStringc.toString()a.toString()b.toString()CCCABB的串联。因此,我在类ABC中定义了一个静态方法,返回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
    

    提前感谢您的时间和帮助。

2 个答案:

答案 0 :(得分:2)

有几种方法可以解决这个问题。

  1. 如果你的语言支持它(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"来获得很酷的东西。如果你没有涵盖所有的情况,编译器会警告你,所以你有效地得到与抽象方法相同的编译时保证。

  2. 一般来说,您需要的是映射类型的方法,所以您也可以只需使用地图。在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,这样您就不会有多个词典。

  3. 另一种选择(同样是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();
        }
    }
    
  4. 但是现在您已使用toString内容更新了问题,我不再确定您的实际目标是什么。 :)

答案 1 :(得分:0)

我可能会误解,但我会在shape类中有一个抽象方法,它在每个子类中被重写。然后,使用对象数组,可以根据sideNumber()方法返回的值对它们进行排序。然后只需遍历排序的数组,在每个数组上调用get颜色。