Thread: Exposing an aggregatee interface

  1. #1
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446

    Exposing an aggregatee interface

    This is probably a silly question, but I'm becoming suspicious I'm not realizing some better design.

    On a few cases, I have classes designed with a rich interface being used as aggregatees on other classes:

    Code:
    class CBeing {
        /* ... */
    private:
        CInventory inv_;
    };
    CInventory has a well delineated interface. Functions to equip and unequip items, drop and pick them, and much more.

    The above example forces me to expose CInventory interface by adding to CBeing interface function members that basically all they do is call inv_ own methods. Only a very small subset of CInventory interface will not be exposed through CBeing. Note this is meant to be an aggregation. inv_ will be destroyed when CBeing is destroyed.

    It's not that it shocks me. However, it makes me suspicious that I'm failing to realize some other better choice than carrying over to the aggregator an aggregatee's interface.

    Is there?
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >Is there?
    If you find yourself constantly wrapping the same public interface around members, you might do better with inheritance instead.
    My best code is written with the delete key.

  3. #3
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    hmm... I think you are right. It's not that Being is-a type of Inventory. Being has an Inventory. However... I end up proving the former if I carry over almost all of its interface.

    Food for thought... Thanks once again Prelude.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  4. #4
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >It's not that Being is-a type of Inventory.
    True. There are two schools of thought on this. First, is-a is a .......... to adhere to in the real world. Second, if is-a doesn't apply but you think inheritance could simplify your life, chances are good that your owning class' interface could be improved so that instead of just wrapping calls to the owned class' interface, you design an interface that still uses the owned class without duplicating its design. That usually results in more fluid interfaces across the board. It takes a great deal more effort though.
    My best code is written with the delete key.

  5. #5
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    I hear you. I remember browsing some time ago through these issues with the (i think) classic "A penguin is not a bird" OOP discussion.

    I'll reconsider how I will be better served. Thanks.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  6. #6
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >classic "A penguin is not a bird" OOP discussion.
    Or rather, all birds don't fly.
    My best code is written with the delete key.

  7. #7
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Exactly hehe.

    But it did bring about the whole issue of not always the code reflecting reality. Is-a and Has-a relationships not being something we really want to draw from the real world all the time.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  8. #8
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    I've solved problems like this in a variety of ways, this is one possibility as well:

    Code:
    class CBeing {
    
    public:
    
       class CInventory{
          /* ... */
       } inventory;
    
    private:
       /* ... */
    };
    I also make CInventory's copy constructor and assignment operator private so nobody can directly assign to a CBeing's inventory, but in this way they can use myBeing.inventory.AddItem() and the like.

    I'd only do this when the classes were strongly coupled, and the contained class had no purpose except to be a member of the containing class (in this example, I'd only use it if Inventory made no sense if it was separated from a Being).

    Public member variables are not universally bad; I tend to avoid them whenever possible for primitives, but a public member object, especially one that cannot be altered with copy construction or assignment, can be used at times, and in general I'd prefer that over a straight duplication of the interface.
    Last edited by Cat; 11-20-2006 at 07:45 PM.
    You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards.

  9. #9
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Yes. That's a possibility as well. It is a fact CInventory is only going to be used with CBeing. It has no meaning as a standalone class.

    The only reason I devised it as a class is that I was confident that I would want one day or another to reuse it. Getting rid of the class altogether and simply merging it into Cbeing is another possibility I'm seriously pondering. CInventory doesn't inherit or derives. It's sole purpose is to exist inside CBeing.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  10. #10
    Registered User
    Join Date
    May 2003
    Posts
    1,619
    If you wanted to maximize its reuse you could always just make a public member variable of type CInventory. Public member variables don't always break encapsulation; in this case the public interface of the Inventory is part of the public interface of the Being. The Inventory isn't just an implementation detail (which should be hidden), it forms an important part of the public interface (which must be exposed).

    If you wanted to couple CInventory to CBeing a little less tightly, and be the most const-correct, you could:
    * Make an abstract base class IInventory that describes the Inventory interface,
    * Make a private reference to IInventory in CBeing,
    * Derive the CInventory from IInventory,
    * Make functions IInventory& Inventory() and const IInventory& Inventory() const that merely return the reference.
    Last edited by Cat; 11-21-2006 at 02:01 AM.
    You ever try a pink golf ball, Wally? Why, the wind shear on a pink ball alone can take the head clean off a 90 pound midget at 300 yards.

  11. #11
    Registered User
    Join Date
    Jun 2004
    Posts
    201
    Quote Originally Posted by Cat
    * Make functions IInventory& Inventory() and const IInventory& Inventory() const that merely return the reference.
    thats what I would do. Just make a GetInventory() function that returns the interface. Then you can control with friend what classes can change the inventory

  12. #12
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    The interface is in fact the best option. No need to use friendship though. I would be coupling the classes all the more tighter (which was what the interface was aiming against in the first place).

    The solution is perfect because I can hide a very small part of CInventory interface that I don't want visible to CBeing users.

    Thanks everyone.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How to get RSSI value, send to sensor, sensor receive package, repackage it?
    By techissue2008 in forum Networking/Device Communication
    Replies: 1
    Last Post: 03-04-2009, 10:13 AM
  2. Calling IRichEditOle interface methods
    By Niara in forum C Programming
    Replies: 2
    Last Post: 01-16-2009, 01:23 PM
  3. Cannot get interface flags: Invalid argument
    By nasim751 in forum C Programming
    Replies: 3
    Last Post: 04-14-2008, 02:29 AM
  4. game user interface
    By DavidP in forum Game Programming
    Replies: 3
    Last Post: 06-19-2004, 12:44 PM
  5. OOP in C
    By lyx in forum C Programming
    Replies: 4
    Last Post: 11-23-2003, 01:12 PM