一个棘手的OOP问题,我从来没有想过

A tricky OOP problem I never got my head around

本文关键字:问题 OOP 从来没有想过 一个      更新时间:2023-10-16

假设我有两个.cpp文件:橙子.cpp篮子.cpp。他们分别有orange类和basket类。我的main程序生成许多baskets进而产生许多oranges。所以基本上,main将有许多Baskets对象;baskets将有许多Oranges的对象.如果我在orange中有一个函数需要知道篮子的颜色,我将如何找到篮子的颜色?

橘子.cpp

class oranges
{
    void whichColorBasket()
    {
        // get the color of the basket the orange is in...?
    }
}

篮子.cpp

class basket
{
    int color;
    void basket()
    {
        for(int i = 0; i < 10; i++)              
            oranges *o = new oranges;
    }
}

我知道我的语法可能并不完美,但是我将如何从orange中的函数访问basket的数据成员(orange是由basket创建的对象)。

发送颜色参数不是一个选项,因为orange太多,并且basket的颜色可能会在运行时更改。

我在某处读到静态函数可以解决问题,但它们只有在同一个.cpp文件中时才有效。

那么,我该怎么办?

静态函数几乎肯定不是这里的答案。

您可能需要将对"父"Basket对象的引用传递给Oranges对象,然后它可以查询该对象以查找颜色。

例如:

class Basket
{
public:
    void Basket() {
        Oranges *o = new Oranges(*this);
    }
    color getColor() const { ... }
};

class Oranges
{
private:
    const Basket &myBasket;
public:
    Oranges(const Basket &b) : myBasket(b) {} // Store reference
    color getColor() const { return myBasket.getColor(); }  // Interrogate my basket
};

是使用指针还是引用将取决于Oranges是否可以在 Basket s 之间移动。

你需要一个橙色的引用,指向橙色所在的篮子

class oranges{
    basket* b;
    int whichColorBasket() {
        return b->color;
    }
}

class basket{
     int color;
     void basket(){
         for(int i=0;i<10;i++){         
              oranges *o=new oranges;
              o->b = &this;
         }
     } 
}

我在这里忽略了内存泄漏

您需要以某种方式将橙子绑定到它们所属的篮子 - 例如,通过将指针传递给篮子。如何做到这一点将取决于橙子在其生命周期中是否可以改变它们与背胶的结合,以及是否可以在它中的所有橙子被销毁之前销毁背胶。

假设橙子永远不会超过篮子

,也永远不会改变篮子,你这样做:

class oranges{
public:
  oranges( backet* object ) { belongsTo = object; }
  void whichColorBasket() {
      here get belongsTo->color;
  }         
private:
  backet* belongsTo;
 };
 class basket{
     int color;
     void basket(){
         for(int i=0;i<10;i++)              
            oranges *o=new oranges( this ); //pass "current object"
     }
 };

您的oranges对象应该有一个实例变量basket表示它所在的篮子。添加一个方法putInBasket,该方法获取一个篮子并将变量设置为它所在的篮子。然后橙色查看whichColorBasket方法中的变量。如果basket NULL它不在篮子里。

但是,这不是最好的设计,因为它提供了不一致的可能性。篮子可能认为它有一个橙子,但橙子的basket指针可能指向不同的篮子。orange真的应该知道它所在的篮子的颜色吗?用例是什么?如果你只处理篮子,并且你有一个橙子,也许篮子应该有一个isOrangeHere的方法,它告诉你是否有一个给定的橙子在那里。您在所有篮子上调用它,然后取返回 true 的篮子的颜色。

简单的答案是你没有。 如果有必要,有某处设计中存在问题:什么样的橙色会知道它在什么篮子里吗? 如果橙色不在一篮子?

如果您需要以某种方式支持这一点,"适当的"解决方案将是类似于观察者模式的东西;你水果将是其容器的观察者;当您将水果放入容器中,容器将注册到水果,当你把水果拿出来时,容器会取消注册。 然后,客户可以向水果询问他们当前的水果容器,随便问。

向 Orange 添加一个属性,其中包含对父篮子的引用。在将橙子添加到篮子的方法中,还将父项设置为篮子。

class oranges{
    basket* basket;
    void oranged(basket* bask)
    {
       basket = bask;
    }
    int whichColorBasket() {
       return basket->color;
    }
}
class basket{
     int color;
     void basket(){
         for(int i=0;i<10;i++)              
              oranges *o=new oranges(&this);
     }         
}

此语法可能是错误的,但这是通常的做法。

由于您正在使用C++因此请在橙子中使用指针。 int *basket_color;然后只需为它分配篮子颜色的地址basket_color = &color

避免耦合的方法是询问每个篮子是否包含特定的橙色。如果是,请检查其颜色。

为什么橙色应该关心篮子的颜色?另一个篮子里的苹果呢?他们也感兴趣吗?

您的oranges类可以有一个引用包含它的篮子的 basket 成员变量。然后,当一个oranges对象想知道它所包含的篮子的颜色时,它只是调用得到myBasket.color的值。

oranges构造函数必须初始化此成员变量,因此它需要一个basket参数。

编辑:完全重做了这个解决方案,因为我错过了一个关键约束。

另一种可能的方法是将成员变量添加到orange类中,如下所示:

class oranges
{
    private:
    int m_nBasketID;
    public:
    oranges(int nID = 0)
    {
       m_nBasketID = nID;
    }
    void whichColorBasket() 
    {
        return gBasketList[m_nBasketID].color;
    }
}

并在basket类中创建oranges时设置值,如下所示:

class basket
{
   static unsigned int nBasketID;
 public:
 int color;
 void basket()
 {
     //First basket will have ID = 1 because
     //0 is reserved for unknown/uninitialized state.
     nBasketID++;
     for(int i=0;i<10;i++)              
          oranges *o=new oranges(nBasketID);
     gBasketList.push_back(*this);
 }

其他修改如下:

unsigned int basket::nBasketID = 0;
std::vector<basket> gBasketList;

我在这里做了几个假设:

  1. 有一个已知值(如零)可用于表示未知/未初始化的颜色状态。此值可以在 oranges 的构造函数中使用默认值。
  2. oranges创建不会切换篮子。如果需要解决此用例,则可以从原始basket中删除orange并向目标basekt添加新或提供成员函数来处理这种情况等。