6

我想知道公共墙(位于相邻房间)和房间之间的关系。
据我所知,房间与其墙壁之间的关系是Composition not Aggregation(我说得对吗?)

And according to the definition of 组合 the contained object can't be shared between two containers, whereas in 聚合 it is possible

现在我很困惑,什么是表示公共墙壁和旁边房间之间关系的最佳建模方法?

如果您可以提供一些代码的建议,将不胜感激。

|--------|--------|

方法1:

(wall class ---- room class) /Composition

方法2:

wall class ----- room class /Aggregation

方法3:

我们有一个墙类和一个公共墙类,公共墙类继承自墙类

adjoining room class ---- (1) Common wall class /Aggregation
adjoining room class ---- (6) wall class / composition

方法 4: 我是开发人员而不是设计师 :) 所以这是我的想法:

class Room 
{
  private wall _firstwall  ;
  private wall _secondtwall;
  private wall _thirdwall  ; 
  private wall _commonwall ;

public Room( CommonWall commonwall)
 {
 _firstwall=new Wall();
 _secondtwall=new Wall();
 _thirdwall=new Wall();
 _commonwall=commonwall;
 }

}

Class CommonWall:Wall
{
 //...
}

// 在某个地方:

 static void main()
{
  Wall _commonWall=new Wall();
  Room room1=new Room(_commonWall);
  Room room2=new Room(_commonWall);
  Room [] adjacentRoom =new Room[2]{room1,room2};
}

编辑1: 我认为这是一个明确的问题,但只是为了更清楚:

问题的重点是找出对同时是两个其他对象的组件的对象的关系建模的最佳模式或方法

关于我的例子:我的意思是“房间”吗?当然,我的意思是一个封闭的方形房间,有 4 面墙和一扇门。但在这种情况下,其中一堵墙是公共墙,由两个相邻的房间共用。

4

6 回答 6

16

你关于房间和墙的问题的答案就是这个问题的答案:“没有房间,墙能存在吗?”

我相信您的方案正在使用聚合。没有房间,墙还能存在吗?当然可以。一个人可以通过摧毁三堵墙来摧毁房间,但剩下的那堵墙是独立的。我认为我们现在只剩下语义了。这个答案可能会根据场景中查看墙壁的方式而改变。

链接显示了一种简洁的思考方式:

  1. A “拥有” B =组合:B 在没有 A 的系统中没有任何意义或目的
  2. A “使用” B = Aggregation:B 独立于(概念上)存在于 A

同样在这里

聚合意味着子节点可以独立于父节点而存在的关系。示例:班级(父母)和学生(孩子)。删除班级,学生仍然存在。

组合意味着孩子不能独立于父母而存在的关系。示例:房屋(父)和房间(子)。房间不存在独立于房屋

来自维基百科

聚合与普通组合的不同之处在于它并不意味着所有权。在组合中,当拥有对象被销毁时,包含的对象也会被销毁。在聚合中,这不一定是真的。例如,一所大学拥有多个系(例如化学),每个系都有许多教授。如果大学关闭,这些系将不复存在,但这些系的教授将继续存在。因此,大学可以看作是系的组合,而系则是教授的集合。此外,教授可以在多个系工作,但一个系不能隶属于多个大学。

于 2012-06-28T00:33:03.640 回答
2

Room 和 Wall 之间存在多对多的关系。(一堵墙可以用在两个房间里,一个房间可以有很多墙。

我建议不要使用像“CommonWall”这样的类,而是使用映射对象和两个一对多关系来解决这个多对多问题。

public class Room 
{
public List<Wall> Walls{get;set;}

}

public class Wall
{
decimal length;
decimal width;
public List<Room> Rooms{get;set;}
}

public class RoomWallMapping
{
public int MappingID;
public Wall {get;set;}
public Room{get;set;}
}
于 2012-07-05T09:20:35.660 回答
2

鲍勃霍恩在这里提出了一个观点,当一堵墙可以独立于房间存在时,它必须是一个聚合体。

但是请记住,您模拟了您希望如何查看/操作它们,因此您还可以决定您主要关心您的房间并将墙壁视为房间的副作用,那么这就是一个组合。

聚合模型

您建造墙壁并定义您的房间,您的房间就是墙壁之间的空间。

这样想,房间不需要有 4 面墙,它只是任意一组墙:开放式房间可以有 3 面墙,而 L 形封闭房间可能有 6 面墙。

这是建筑师或建筑商将采用的表示。

组合模型

你想把房间看成一个有墙壁的空间,那么你真正关心的是从房间内侧看到的墙壁。在这种情况下,如果另一个房间有共同的墙壁,您就不会开车,当您摧毁您的房间时,墙壁的内侧也会随之消失。

共享墙变成了两个房间墙的聚合。

如果您正在计划展览并想要定义绘画的放置位置,这可能是正确的表示。

为最适合您的需求建模

最后,您对表示进行建模,从而进行简化。同样,在对表示建模时没有正确最佳答案,您应该根据需要对表示进行建模。

如果您想购买汽车,您倾向于将书定义为由其页面组成,当您处置它时,您会处置每一页。如果您想打印一本书,您倾向于将您的零件作为由页面组成的聚合对开页,如果一个对开页打印错误,您可以从库存中取出另一个以组装成最终的书。

于 2012-07-05T21:12:28.227 回答
1

这取决于。墙总是有两个面。;-)

在这种情况下,我会使用使用属性注入或构造函数注入,例如

public class Room
{
    public List<Wall> Walls { get; set; }
    public Room ( IEnumerable<Wall> walls )
    {
        Walls = new List<Wall>(walls);
    }
}

然后使用创建模式(例如构建器模式)来使用共享墙来构建房间。

于 2012-07-02T22:26:03.543 回答
1

如果这与真正的问题很接近,我想我不会想用普通的墙壁来组成房间。我更有可能收集 RoomComponents 或 IRoomComponents 将使用构造函数注入或属性注入注入。也有可能使用注入框架来组成房间,以便框架负责对象的生命周期。

如果有一秒钟我会想象问题真的很简单,只有房间和墙壁,那么我猜你的方法 #4 看起来像是要走的路。我不确定什么是合适的名称,因为那里既有聚合又有组合。另一种方法是将公共墙设置为属性(如上所述的属性注入),而不是通过构造函数。

最后,如果我像这个线程中的其他人一样进入幻想世界,那么我很快就会意识到你所有的墙都应该是普通的墙!假设有人在现有房间的一堵墙周围建造了另外三堵墙-> bam 你有一个新的房间和一个新的公共墙。现在要做什么?您可能想将现有墙更改为新的 CommonWall 对吧?因此,在这种情况下,将墙壁作为属性似乎是不可避免的,否则每次您决定建造一个相邻的房间时,您都必须重新创建所有相邻的房间。

于 2012-07-09T06:39:05.147 回答
1

你如何处理房间和墙壁取决于手头的任务。

我将用两个例子来说明这一点,然后我会回过头来回答你问题的实际“要点”。

第一种方法(导航 1 层建筑):

目标:我想告诉机器人从其当前位置移动到复制室。

我确定建筑物的尺寸,例如 100 英尺乘以 100 英尺。选择一个轴,并制作一个点网格。机器人可以从位置 (50,50) 开始。接下来,我创建一个图形,其中每条边代表从该节点到相应节点的向北、向东、向南或向西的一步。被墙隔开的节点有无限的重量,即不能通过。

该图在邻接列表中表示。

现在我将 Room 定义为一个多边形并列出它的顶点。要测试机器人是否在房间内,它必须在房间多边形定义的区域内。在这种情况下,房间可能会重叠,尤其是因为在现实生活中站在门口可能意味着您在任一房间。

我的机器人现在可以在建筑物中导航、移动家具以及它想做的任何其他事情。

第二种方法:(面向对象)

  • 建造
    • 特性
      • 宽度、长度、高度、地理空间坐标、年龄等。
    • 外墙
      • 可能是从 OuterWall 继承的 BrickWall、GlassWall、ConcreteWall 等
      • 属性:位置、厚度等
      • 方法:DemolishWall()、PaintExterior(Color C)等。
    • 内墙
      • 可能是 NorthSouthWall 或 EastWestWall。
      • 属性:hasDoorway、N/E色、S/W色等。
    • 房间
      • 属性:名称、位置、宽度、长度等。

请注意,在这些示例中,房间都没有直接引用它们的墙壁。

现在到你问题的实际点。如果两个对象具有共享资源,应该如何处理。

并行编程以各种不同的方式处理共享资源。

  1. 为每个对象提供对共享资源的引用,确保同步或以其他方式处理共享资源上的并发行为。
  2. 使共享资源可作为全局变量或通过单例对象或另一个类中的静态资源,甚至是内存或文件系统中的特定位置对每个对象可用。
  3. 以预定义的顺序或在预定义的时间在并发部分之间传递共享资源。

想象一下每两个房间之间有一个共用浴室的酒店:

HotelGuest A = new HotelGuest( new BusinessMan() );
HotelGuest B = new HotelGuest( new Programmer() );

A.Room = 101;
A.Bathroom = 7;
A.BathroomKey = getBathroomKey(7);

B.Room = 102;
B.Bathroom = 7;
B.BathroomKey = getBathroomKey(7);

//Asynchronously
A.RunDoBusinessStuff();
B.RunProgrammerStuff();

//but each has to lock bathroom7 when they use it, or it could be embarrassing.

但是在上面的例子中,浴室怎么知道哪两个HotelGuests有它的钥匙呢?

  1. 用当前客人和他们拥有的钥匙创建一个数据库,浴室可以查询数据库(或列表)。
  2. 在浴室属性中存储对 A 和 B 的引用。(想象一下浴室里的白板列出了它的“租户”)。
于 2012-07-03T00:00:14.117 回答