Re: Design question: Multiplying singletons



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



.



Relevant Pages

  • Re: realtime rl v.2
    ... You have to make a choice between a Rendering Engine knowing how to render objects of different type, or each object knowing how to render itself to a surface. ... If you want to use the second, the surface should be separate from the object and can be used like Object.Render;. ... Start with (Private Properties, Public Properties, Constructors, Private/Protected Methods, Public Methods; for forms add Form Events and Control Events). ... To find it yourself, click Debug->Exceptions and then find the above exception, click the left check box and ok. ...
    (rec.games.roguelike.development)
  • Re: realtime rl v.2
    ... Separate your Objects from their rendering implementation, ... Rendering Engine knowing how to render objects of different type, ... private with the 'private' keyword. ... yourself, click Debug->Exceptions and then find the above exception, click ...
    (rec.games.roguelike.development)
  • Re: static class inheritance, generalized
    ... private Bar _bar; ... private string _val; ... private Foo _container; ... horrible the more readability and clarity of the code goes out the ...
    (microsoft.public.dotnet.languages.csharp)
  • =?windows-1252?Q?It_can_be_tough_to_know_whom_to_trust_in_Cambodia=92?= =?windows-1252?Q?s_s
    ... PHNOM Penh's private eye points to a bar girl and then to a man in ... The man has been hunched over his drink since we arrived at the bar, ... Felipe Ylan Cordell, one of three names the detective goes by, started ... Cordell has only found one case of a target ...
    (soc.culture.cambodia)
  • Re: Alternativen zum "m_"-Praefix?
    ... Private bar As String ... Public ReadOnly Property Bar() As String ... End Property ... ist vom Typ Integer, also abgeleitet von Index und nicht von Integer. ...
    (microsoft.public.de.german.entwickler.dotnet.vb)