对象关系设计

3

我恰巧考虑到一个可能听起来很琐碎但我不知道为什么我觉得相当困惑的面向对象概念。

无论如何,举个例子,如果我有一个动物类和一个位置类。我只允许一只动物在任何时候都在一个位置上。所以这有点像1对1的关系。同时,我希望动物和位置类不需要某种双向引用,以便它们保持松耦合。如果说我有这个:

class Animal {
   private Location loc;

   public Animal(int x, int y) {
      loc = new Location(x,y);
   }

   public static newAnimal(Location[][] map, int x, int y) {
      if(map[x][y] != null) {
         return new Animal(x, y);
      } else return null;
}

class Location extends Point {
   public Location(int x, int y) {
      super(x, y);
   }
}

public static void main(String[] args) {
   //populates a map
   Location[][] map = new Location[10][10];
   for(int x=0; x<10; x++) {
      for(int y=0; y<10; y++) {
         map[x][y] = new Location(x, y);
      }
   }

   Animal dog = new Animal(2, 4);    //dog is at location 2,4
   Animal cat = new Animal(5, 6);    //cat is at location 5,6

   //But this does not restrict a constraint requirement that there should only be one animal at any one point
   Animal horse = new Animal(2, 4);    //now, horse is at the same location as dog but we only wanted one location to have one animal

   Animal rabbit = Animal.newAnimal(map, 20, 50);    //rabbit is null because it is out of the map size
}

从这里,我预见到了两个问题。
首先,因为我的位置不知道是否已经有动物在上面,许多动物都可以指向地图数组上的同一位置。这将违反我想要的1-1多重性约束。在我的情况下,我让动物拥有位置。这可能是发生这种情况的原因。如果我让位置拥有动物,这个问题就可以解决。但是,在某种情况下,如果我想知道我的动物在哪里,我需要遍历整个地图才能找到其中一个动物的位置?或者,我可以保持双向引用,但这会导致类高度耦合。
我感觉第二个问题可能是动物类中的设计问题。我有一个静态的newAnimal()方法来实例化新动物。我这样做是因为我认为允许调用者直接从构造函数创建新的Animal实例可能会导致超出范围的坐标输入。但我仍然觉得设计非常尴尬。
我在我的示例中使用Java代码。我正在考虑类对象本身内部的设计,而没有涉及数据库。
任何改进我提出的两个问题的建议都可以很好地解决。谢谢!

树上的猴子知道自己在哪棵树上,甚至可能按照自己的方式数出剩下多少香蕉,但树并不包含猴子。 - Affe
@Affe,谢谢你留下了评论。我还是有些困惑,请问你能再详细解释一下吗?非常感谢! - Carven
这是我的说法,如果您的业务/应用程序领域包括共享状态的两个事物,则它们根据定义是耦合的。费力地尝试以其他方式对其进行建模有何优点? - Affe
是的,它们有些耦合,但我希望它们不会非常紧密地耦合,这样实现就需要确保所有引用完整性。特别是当存在双向关联时。 - Carven
4个回答

2
1.Location/Map in our case is a real world object and has boundaries.
2.Map can not hold more than one animal at any pont
3.An animal can not occupy more than one location

以下是与该问题相关的事实。
位置可以被视为矩阵,一个二维数组。目前我们假设在某个时间点上,一个动物只占据一个单元格(一个单元),不多也不少。
这个二维数组是由动物组成的(只能包含Animal对象),因此它们的容纳是真实的,没有两个动物可以占据同一空间-它必须替换现有的动物才能占据该空间。
此外,动物的位置属性应该更新。
或者,可以编写LocationManagerClass来存储和管理地图上的动物占用情况。但是,需要进一步评估它是否接近“空间占用”的真实情况。

这是个不错的想法!但是在二维数组中,动物被随意地放置。但是当我需要知道特定动物的位置时,我必须遍历整个二维数组才能找到它的当前位置。这样做是否过于昂贵,仅为了找出其当前位置?而且,如果地图变得更大,循环也会变得更重。 - Carven
2
你可以保留一个动物/位置的字典,其中保存每个动物的位置... 然后你就可以 O(1) 访问它的位置了。 - Yochai Timmer
@xEnOn,是的,你说得完全正确,这会很昂贵。这就是为什么我建议“此外,动物的位置属性应该被更新”。在现实世界中,如果我占据了一个空间,如果有人想找到我在哪里,那么他需要搜索整个地图-没有其他选择。但我们通常不喜欢这样做-所以我们有技巧-比如我们说“我就在你身后”,“我在家里”等(我知道)。如果我在沙漠中没有这方面的知识,我会说“我迷路了”。那么对于寻找者来说,找到我就很困难了。因此,将位置信息附加到动物对象上始终是一个好主意 :) - WinW
@xEnOn 一个可能的修改是动物/任何对象占据空间。因此,数组可以是类型Interface:IOccupier,其中Animal实现IOccupier,Car实现IOccupier。这样你就可以拥有可扩展性。 - WinW

1
我会创建一个独立的接口+类来管理/维护关系,并拥有添加新动物或将动物移动到其他位置的方法。这样,您可以轻松检查和维护先决条件/后置条件。此外,在这种情况下,我会保持Animal和Location不可变。 使用接口和类将更容易实现不同的关系实现:Map、DB、文件等。

0
你可以使用类似以前的答案,但是换成其他数据结构而不是2D数组。比如稀疏数组、有序列表或哈希表。这将提供更快的查找速度,但插入或动物移动速度较慢。它仍然可以执行任何位置不超过1个动物的要求。

0

为什么你想让Animal类包含Location?

另一种选择是只在Animal类中拥有Animal属性。Location类已经很好了。可以再创建一个名为Map的第三个类,来管理地图上的位置和每个位置上的动物。

这个问题的C++代码可能如下所示:

class Animal
{
    public:

            Animal(char *name);
            ~Animal();

            char *getName();
    private:

            char *name;

};

//这里我没有使用Location类,而是使用了x,y。你可以进行这个小改变。

class Map
{

    private:

        Animal *animalLocation[10][10];


    public:
        //Note this function will check if any Animal exists at the specified (x,y). 
        void addAnimal(int x, int y, void *animal);
        void* getAnimal(int x, int y);

        Map();
        ~Map();

};


这也是一个相当不错的方法!但是有一件事,如果我想找到特定动物的位置,我仍然必须循环整个地图数组才能找到它在哪里,对吗?无论我使用什么样的设计,这是我无法逃避的吗?当然,具有位置和动物之间双向关系可以避免此循环,但我不知道哪种更值得。 - Carven
是的,你说得对。如果只需要根据位置搜索动物,那么这种方法是理想的。但如果矩阵大小为50x50,遍历整个矩阵所需时间可能可以忽略不计。此外,您应该考虑此请求的频率。所有这些都取决于您所针对的用例。 - Chandan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接