从单个对象继承的不同类型的集合与单个超级对象集合

时间:2010-10-15 15:55:53

标签: java ibatis

想象一下以下情况。

class Shape
{
    // methods of Class Shape
}

class Circle extends Shape
{
   // methods of Class Shape
   // methods of Class Circle 
}

class Square extends Shape
{
  // methods of Class Shape
  // methods of Class Square 
}

class Canvas  // This class should a bucket of objects that belong to Square and Circle 
{
  // Declaring a single list of supertype
  List<Shape> heterogeneousCollection;

  // Declaring two separate lists
  List<Cirlce> homogeneousCollection;
  List<Square> homogeneousCollection; 
}

对应的关系模式如下

  • 表格形状包含主信息
  • Tables Circle&amp; Square通过外键引用的方式丰富Shape中的数据(Circle&amp; Square是不同列的不相交集)
  • Table Canvas是一种数据聚合
  • Canvas加入Circle(1..n基数)
  • Canvas加入Square(1..n基数)

哪种方法更好“声明单个超类型列表(异构集合)”或“声明两个单独的列表(两个不同的同类集合)”

我在做出决定时正在考虑以下几点。

  1. 从数据库中读取时,如何填充对象Canvas?
  2. 考虑一种避免N + 1问题并从单个查询中读取的方法,如

    SELECT * FROM 
    Canvas INNER JOIN Circle ON ..  
    Canvas INNER JOIN Square ON ..  
    Circle INNER JOIN Shape ON ..  
    Square INNER JOIN Shape ON ..   
    

    现在,对于Canvas的每一条记录,我们最终得到(B + C)行。但是,使用多个ORM工具,可以将Circle和Square中的组不同数据集分成两个单独的列表。 (我在这里考虑iBatis)

    1. 我们如何处理这些对象的几个功能?
      对我们计划处理UI功能以在对象Canvas中显示数据的情况进行成像。除了Circle和Square之间的常用功能,它们中的每一个都可以具有不同的功能。例如,Square可以有getLengthOfSide(),而Circle可以有getRadius()。如果我们使用异构列表,我们最终可能会在需要访问这些函数的每个地方使用强制转换运算符。

      Class Canvas  
      {  
          void drawAll()  
          {  
              for (Shape s : heterogeneousCollection)  
              {  
                  if (s instanceof Circle)  
                  {  
                      s.draw(); // common function present in Shape also  
                      s.xyz(); //  specific to Circle  
                  }  
                  if (s instanceof Square)  
                  {  
                      s.draw(); // common function present in Shape also  
                      s.abc(); //  specific to Square  
                  }  
              }   
          }  
      }  
      
    2. 如果是两个同类列表,我们可能会分别为每个列表分别使用两个for循环。

      然而,如果我们需要添加一种新的形状(比如说三角形),它会影响Canvas,我觉得这是设计缺陷的结果,Java可能会配备这个来解决这个问题。请注意这一点。任何对书籍/链接的参考都会有很大的帮助。只是想告诉大家,这不是学校的任务,我正在认真考虑各种解决方案。请原谅我一个长期的问题。

      PS:排除了另一个解决方案List<? extends Shape>,因为我们无法在此集合中插入任何对象。

2 个答案:

答案 0 :(得分:1)

当我们掌握一般信息而非具体事实时,很难给出解决方案。例如,xyz()和abc()方法。它们是什么,为什么?在你的例子中,它们似乎有类似的用法,所以我考虑在Shape中定义一个名为doS​​omethingSpecific()的抽象方法,因此它将由所有Shape子类实现。 现在你的代码是:

   void drawAll()  
       {  
       for (Shape s : heterogeneousCollection)  
           {
           s.draw();                // common function present in Shape also  
           s.doSomethingSpecific(); //  specific to each implementation  
           }   
       }  

我尽可能选择异构集合。我非常不喜欢instanceof因为你指出的原因 - 当我们将Triangle添加到混合中时会发生什么。

答案 1 :(得分:0)

假设您有多个地方合法地需要独立处理Circle和Square,我会通过应用Visitor Pattern来处理异构集合

这样做的好处是,如果您稍后添加Triangle,那么当您添加方法时 T visitTriangle(Triangle triangle);访问者,在更新每个访问者之前,您的代码将无法编译,从而避免了令人讨厌的运行时意外。

但是......如果你真的只是在讨论处理Circle和Square的单个实例,那么在这里应用Visitor是过度的,我会考虑为doSomeSpecificUiThing()的Shape添加一个抽象方法。 / p>

它看起来像这样:

class ShapeVisitor<T>
{
    T visitCircle(Circle circle);
    T visitSquare(Square square);
}

class Shape
{
    abstract <T> T accept(ShapeVisitor<T> visitor);

    // methods of Class Shape
}

class Circle extends Shape
{
   <T> T accept(ShapeVisitor<T> visitor) {
       return visitor.visitCircle(this);
   }

   // methods of Class Circle 
}

class Square extends Shape
{
   <T> T accept(ShapeVisitor<T> visitor) {
       return visitor.visitSquare(this);
   }

  // methods of Class Square 
}

Class Canvas  
{  
    void drawAll()  
    {  
        for (Shape s : heterogeneousCollection)  
        {  
            s.draw();
            s.accept(new ShapeVisitor<Void>() {
                @Override Void visitCircle(Circle circle) {
                    circle.xyz();
                    return null;
                }

                @Override Void visitSquare(Square square) {
                    square.abc();
                    return null;
                }
            }
        }   
    }  
}