Re: Design question: Multiplying singletons



In article <Gb5Yh.5152$Zm.5122@trndny03>, H. S. Lahman
<h.lahman@xxxxxxxxxxx> wrote:

Responding to KelvSYC...

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...


This is a valid concern in one-to-many relationships - I'd have to take
note of that.

But suppose the relationships were one-to-one - that is, you could fold
everything in B (or C) back to A, but then A would simply balloon in
size or manageability (B or C may or may not be singleton, which would
be moot). Going back to the original question, with the one-to-one
relationship in mind, how would you keep track of the A associated with
a B (or C) if A was no longer singleton? Would the controller idea
work?

Ok, let's take a look at it:

1 R1 1
[A] ------------- [B]
| 1
|
| R2
|
| 1
[C]

If the relationships are 1:1 as above, then a given A can only be
related to exactly one B and one C at a time. Since A is a Singleton,
there can only be one instance of A. So exactly one B and one C is
accessible from that single instance of A.

Similarly, a B can be related to only one A and a C can be related to
only one A. Since there is only one A, then the model says that there
can only be on B and one C as well.

That changes as soon as A is not restricted to be a Singleton. Now if
there are N As, there can be N Bs and N Cs. Each A instance can be
related to a different B and C instance. As it happens, since the
relationship is unconditional on both ends, there must be exactly N Bs
and exactly N Cs and each A must be connected to different Bs and Cs.
[If, say, two As were related to the same B, then that B would be
related to two As, violating the A-side 1 multiplicity. If there were
more Bs than As, then some Bs would be unrelated to an A. If there were
less Bs than As, then some As would be unconnected to a B.]

Thus a 1:1 relationship is a very, very strong constraint on the
structure of set connectivity. (A tad pedantic, but I wanted to make
sure we were on the same page.)

So to answer your question, one would usually instantiate each
relationship with a pointer in each class (two in A). To ensure
referential integrity, that pointer would need to be instantiated before
any participant was accessed. That effectively means that one must
create an A, a B, and a C at the same time and assign the four pointers
at that time. ("At the same time" typically means within a single method
scope; otherwise one has to provide other infrastructure to ensure
access will not be premature.)

Typically one would do that with some sort of "factory" object that
created the triplet. That factory object would map to your controller.
But its responsibilities would be limited to instantiation and its
heavy-duty responsibility would be understanding that A, B, anc C needed
to be created as a triplet so that referential integrity could be
enforced by instantiating their relationships.


I would have envisioned that A, B, and C would need to be instantiated
all at once, thus a factory would be needed - but in this case is
two-way referencing necessary (ie. is the pointer in B to A necessary)?
If A, B, C represented some kind of part-whole hierarchy (A being the
whole, B and C being parts), then it seems kind of ugly to have an A
reference in B (as it would make sence to keep references to the parts
in the whole, but not as much to keep the reference to the whole in the
parts).

Suppose we have this:

class AController {
// assume it is singleton
private Array<A> as;
private AssociativeArray<B,A> bMap;
public void instantiateA() {
// instantiate B and C
// instantiate A
// add A instance to as
// add the B instance and A instance to bMap
}

// also some other method that removes stuff from bMap whenever A
gets deallocated, I presume
}

Would this be a good substitute for keeping an A reference in B? Does
it introduce some chicken-and-egg problem that I may have to address?

Collections are a fairly easy extension; one just replaces the pointer
with a collection handle. However, referential integrity now involves
making sure the collection has the /right/ instances at the time of
collaboration. (Once there is one instance available, multiplicity and
conditionality are no help in determining which particular ones must be
around at a given moment in time.)

What's the difference between a one-to-many relationship between A and
B and a one-to-one relationship between A and a collection of Bs?

--
I am only a mirage.
.



Relevant Pages

  • Re: Optimization idea that might not be good OO
    ... success of the operation in the factory, ... already in the cache return a reference to it. ... The difference between a Singleton and an instance held by the Application object is not that big. ... I usually prefer the reference variant. ...
    (comp.lang.php)
  • Re: C# ServicedComponent Singleton
    ... > has released the reference to the object. ... reference a COM+ singleton object. ... Each client creation call will get a reference to the same instance provided ... call will be suspended (activation time-out) whenever another client is ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: lock(...) question
    ... the second thread will simply get a reference to the ... singleton object of thread A. ... The first null check simply avoids the overhead of a lock as you rightly ... lock if the singleton reference were exposed to multiple ...
    (microsoft.public.dotnet.framework)
  • RE: global objects
    ... >> Locking the singleton type is slightly dangerous - it's a public ... >> reference, effectively, so other things may lock the same reference. ... Keeping your locks private is just a good practice thing to do. ... being totally moronic - or at least any worse than the singleton code ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Question on LSP
    ... Sure, the developer must keep track of which type has been assigned to each pointer to manage complexity in creating the design, which is why the 'T' is in T*. ... Subtyping is a relation which does not ... Those object types are completely orthogonal to the semantics of being an object reference. ... aggregate references, is the aggregate of referenced objects or target ...
    (comp.object)