从单个对象继承的单个对象与超级对象的单个集合继承的不同类型的集合 [英] Collections of different types inherited from a single object vs a single collection of super object

查看:57
本文介绍了从单个对象继承的单个对象与超级对象的单个集合继承的不同类型的集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想象一下以下情况.

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; 
}

对应的关系架构如下

  • 表格形状包含主信息
  • 表圈&通过外键引用的方式对Shape中的数据进行平方富集(Circle&-Square是具有不同列的不相交集)
  • 表格画布是一种数据汇总
  • 画布加入Circle(1..n基数)
  • 画布加入Square(1..n基数)

声明一个超类型的单个列表(异构集合)"或声明两个单独的列表(两个不同的同类集合)"是更好的方法

Which is the better approach "Declaring a single list of supertype (heterogeneous collection)" or "Declaring two separate lists (two different homogeneous collections)"

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

I'm considering the following points when making a decision.

  1. 从数据库读取数据时如何填充对象Canvas?

考虑一种避免N + 1问题并从单个查询中读取

Consider a way of avoiding N+1 problem and reading from a single query something like

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)

Now, for every one record of Canvas we end up with (B+C) rows. However, with several ORM tools it is possible of group distinct data sets in Circle and Square into two separate lists. (I'm considering iBatis here)

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

  1. How do we handle several functions on these objects?
    Imaging a case where we are planning to handle a UI function to display data in object Canvas. Apart from common functions between Circle and Square, each of them can have different functions. For example Square can have getLengthOfSide(), whereas Circle can have getRadius(). If we use heterogeneous list, we might end up using a cast operator at every place we need access to these functions.

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  
            }  
        }   
    }  
}  

在有两个同类列表的情况下,每个列表可能分别具有两个不同的for循环.

In case of two homogeneous list we might have two different for loops for each list separately.

但是,如果我们需要添加一种新的形状(例如三角形),它会影响Canvas,我认为这是设计缺陷的结果,Java可能有能力解决这一问题.请对此进行一些说明.对书籍/链接的任何引用都会有很大的帮助.只是想告诉大家,这不是学校的任务,我正在认真研究各种解决方案.请问我一个长问题.

However, if we need to add a new kind of shape (say triangle), it is affecting Canvas, which I feel is a result of design flaw and Java might be equipped to deal with this. Kindly throw some light on this. Any reference to books/links would be of great help. Just wanted to tell you guys that this is not a school assignment and I'm seriously looking at various solutions. Pardon me for a long question.

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

PS: One other solution List<? extends Shape> is ruled out because we cannot insert any objects into this collection.

推荐答案

假设您确实有很多地方需要独立处理Circle和Square,通过应用访问者模式

这样做的好处是,如果以后添加Triangle,则在添加方法时 T visitTriangle(Triangle triangle);对于访问者,直到更新每个访问者,您的代码才会编译,以避免讨厌的运行时意外.

This has the benefit that if you add Triangle later, then when you add a method T visitTriangle(Triangle triangle); to the visitor, your code won't compile until you update every single visitor, avoiding nasty runtime surprises.

但是...如果您真的只是在谈论一个不同的处理Circle和Square的实例,那么在此处应用Visitor是过大的,我只考虑为doSomeSpecificUiThing()的Shape添加一个抽象方法.

However... if you're really only talking about a single instance of processing Circle and Square differently, then applying Visitor here is overkill and I would just consider adding an abstract method to Shape for doSomeSpecificUiThing().

它看起来像这样:

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;
                }
            }
        }   
    }  
}  

这篇关于从单个对象继承的单个对象与超级对象的单个集合继承的不同类型的集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆