Re: Design question: Multiplying singletons
- From: "H. S. Lahman" <h.lahman@xxxxxxxxxxx>
- Date: Wed, 25 Apr 2007 16:59:00 GMT
Responding to KelvSYC...
Suppose you have a singleton class, which has its own object
structure, and so on so forth. Now, referring to some unrelated part
of the object structure is easy, as you only need to get the singleton
instance and access it from there. Here's a Java-esque example:
class A {
private static A instance;
public static A getInstance();
private A();
private B b;
private C c;
public B getB() { return b; }
public C getC() { return c; }
}
What you seem to be describing is:
1 R1 *
[A] ------------- [B]
| 1
|
| R2
|
| *
[C]
where the requirements dictate that only one A may exist no matter how many [B] or [C] objects there are (i.e., R1 and R2 always have the same A on the 1-side for every B and C). So one implements [A] as a Singleton pattern.
All that A::getInstance() is doing is providing reference for [B] or [C] objects to use to instantiate their R1 or R2 relationship. Then A::getB() and A::getC() just provides navigation through A when a B needs to collaborate with a C or vice versa.
The problem is that if there are multiple [B] or [C] objects, one can't provide that navigation with your implementation of A::getB() and A::getC(). That is because the single A instance is actually related to multiple Bs and Cs. So long as the [B] or [C] side is *, then one needs a collection to manage the 1:* relationship and the accessors need to know which particular B or C one is after within the collection: A::getB(bID) and A::getC(cID). So...
class B {
private int foo(C c);
public int bar() { return foo(A.getInstance().getC()); }
}
There's a typo: bar() returns a C. This needs to change to:
class B {
private:
A myA;
int foo(C c);
public:
setA() {myA = A.getInstance();} // probably when B is created
C bar() {
// figure out which C is needed from collaboration context
cID = ...
return foo(myA.getC(cID));
}
}
BTW, the entire implementation of B is not a good idea because it mixes relationship instantiation and collaboration navigation. It also provides implementation dependencies. Instantiation (Who) and navigation (When and What) are different concerns so they usually have business different rules and policies that need to be separated. Your application will be more robust if the concerns are separated and B is defined as:
class B {
private:
A myA;
C myC;
public:
setA (A a) {myA = a;}; // instantiate R1
setC (C c) {myC = c;}; // instantiate R2
void foo () { // access through myC reference };
void bar () {
// figure which C is needed from collaboration context
cID = ...
setC (myA.getC(cID)); // instantiate R2
}
Now instantiating the relationship is quite separate from using it for navigation. Thus the caller of foo() does not need to know which C foo() should currently collaborate with. That is determined separately by invoking setC() from whatever context understands who the participants in the collaboration should be. Conversely, bar() is limited to figuring out which C is currently relevant and it is not concerned with what happens to that C. So bar() does not need to know that foo() collaborates with C.
Note that I also eliminated returns for foo() and bar(). Only knowledge accessors should return values for the caller to use. (A reference to an object that implements a relationship is a referential knowledge attribute, so getC and getB are just knowledge accessors.) When a behavior responsibility returns a value it automatically creates an implementation dependency in the caller on what the callee does.
The major goal of the OO paradigm is to eliminate the hierarchical implementation dependencies of classic functional decomposition. So behavior responsibilities should never return values in well-formed OO applications. Note that in OOA/D message and method are separated and one normally views behavior collaboration as asynchronous because that is the most general description. In that model behavior /can't/ return values because there can be an arbitrary delay between when a message is sent and when the behavior responds to it while the message sender continues processing.
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
hsl@xxxxxxxxxxxxxxxxx
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info@xxxxxxxxxxxxxxxxx for your copy.
Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH
.
- Follow-Ups:
- Re: Design question: Multiplying singletons
- From: kelvSYC
- Re: Design question: Multiplying singletons
- References:
- Design question: Multiplying singletons
- From: kelvSYC
- Design question: Multiplying singletons
- Prev by Date: Re: Modeling events that occur in a game world
- Next by Date: Re: dynamic binding on parameters, how ??
- Previous by thread: Re: Design question: Multiplying singletons
- Next by thread: Re: Design question: Multiplying singletons
- Index(es):
Relevant Pages
|