user17861
user17861

Reputation: 43

What is the correct way to design/implement two (or more) classes that have "has a" relationships with the same object?

Suppose I have a design like this:

Object GUI has two objects: object aManager and object bManager, which don't ever talk to each other.

Both aManager and bManager have object cManager as an attribute (or rather a pointer to cManager). So when aManager modifies its cManager, it's affecting bManager's cManager as well.

My question is what is the correct way to design/implement this?

I was thinking of making cManager as an attribute of GUI, and GUI passes a pointer to cManager when constructing aManager and bManager. But IMHO, GUI has nothing to do with cManager, so why should GUI have it as an attribute?

Is there a specific design pattern I should be using here?

Upvotes: 4

Views: 280

Answers (7)

supercat
supercat

Reputation: 81133

In general, at any moment in time, any mutable object should have exactly one clearly-defined owner (an object will typically have multiple owners throughout its lifetime, with the first of them being the constructor, which then hands ownership to the code that called it, etc.) Anything else which holds a reference to the object should regard that reference as being a reference to an object owned by someone else.

One might think, when going from C++ to Java or .net, "Hey cool--I don't have to worry about object ownership anymore", but that's not true. Ownership of mutable objects is just as relevant in a GC-based system as in a non-GC system. The lack of any means of expressing ownership does not relieve the programmer from the obligation of knowing who owns what. It merely makes it harder to fulfill that obligation.

If a cManager is mutable, then either aManager should own one and bManager hold a reference to it, and think of any changes to its target as affecting aManager's cManager, or bManager should own one (with aManager holding a reference, etc.), or some other entity should own one, with aManager and bManager both thinking of their changes as affecting owned by that other entity.

Even if one uses a language or framework which does not recognize any concept of ownership, always think in such terms when dealing with mutable objects. To do otherwise is to invite confusion and disaster.

Upvotes: 0

Loofer
Loofer

Reputation: 6965

Use singletons with care (or not at all if you want easy tests!)

Upvotes: 1

Bill K
Bill K

Reputation: 62759

I'm going to interpret this as simply as possible, if I'm not answering your question, I apologize.

When you really get the answer to this question, it's your first step to really thinking Object Orientedly.

In OO, when two objects both "has a" 'nother object, it's perfectly acceptable for both to refer to that other object. The trick with OO is that objects have a life of their own, they are fluid and anyone that needs them can keep a reference to them. The object must keep itself "Valid" and maintain stability when being used by many other objects. (This is why immutable objects like String are so great, they are ALWAYS as valid as the second they were created)

The one exception is if you are coding in C++ because then you actually have to manually free objects, that implies an owner that can monitor each object's lifecycle--that makes it really really hard to "Think" in OO in C++.

[Addition] Since you are referring to pointers, I'm thinking you are programming in C++ which is different. In that case, you are right. Make one manager "Own" the lifecycle of your shared object. It must not let that object die until all other references have gone away.

You can also use reference counting. Whenever someone gets a reference to your object, it calls "addReference" or something, whenever it's done it removes the reference. If anyone calls removeReference when the count is 1, the object can clean itself up. That's probably as close as you can come to true OO-style allocation/freeing in C++. It's very error-prone though.

There are libraries to do this kind of stuff I believe.

Upvotes: 1

Tim Frey
Tim Frey

Reputation: 9941

I recommend just passing in cManager as a parameter in your GUI object constructor, but don't maintain a reference to it (Java code here, but you get the idea):

public GUI(CManager cManager)
{
    this.aManager = new AManager(cManager);
    this.bManager = new BManager(cManager);
    // don't bother keeping cManager as a field
}

I don't think either a Singleton or Factory is appropriate here.

Upvotes: 1

Scott Langham
Scott Langham

Reputation: 60361

This is tricky to answer without a discussion about what you want to achieve. But, I'd say, go with getting GUI to hand the pointer to aManager and bManager as you say.

If you're trying to create a GUI and wondering how to get data in and out of it, then I can recommend this: http://codebetter.com/blogs/jeremy.miller/archive/2007/07/25/the-build-your-own-cab-series-table-of-contents.aspx

I think that is mainly written for C# users, but would apply to other languages. I'm guessing this may be more advanced than you need for your first OO application though. I think you're going to have to get yourself a book on OO design and spend some evenings with it.

As a noob, I recommend you don't bother trying to do everything the most perfect correct way first time, but just get something to work. You'll learn with time (and reading a lot) what makes a solution better than others for different criteria. There's no right answer to your question.

Upvotes: 0

JeeBee
JeeBee

Reputation: 17546

You should look into separating your GUI from your model and implementation.

You could make cManager a singleton if there is only ever meant to be one cManager ever, app-wide.

Upvotes: 0

Ben Hoffstein
Ben Hoffstein

Reputation: 103325

You can use the Factory pattern to request a reference to cManager by both aManager and bManager as needed.

http://msdn.microsoft.com/en-us/library/ms954600.aspx

Upvotes: 0

Related Questions