Re: Design question: Multiplying singletons



Responding to KelvSYC...

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)?

No, it depends upon the problem being solved. I was just describing the general case.

If the solution doesn't need navigation in one direction, one does not need to implement or instantiate it. As a general rule in the OO paradigm we only abstract what we need to solve the problem in hand.

I would point out, though, that behavior collaborations are different than knowledge collaborations. While the flow of messages between behaviors may be in one direction when the developer connects the solution dots, that doesn't mean that knowledge access is limited to the same direction as behavior collaborations. Thus all clients needing a B service may navigate through A, but for B to do its thing it may need data from A.

Since relationship implementation is orthogonal to class semantics and it is usually easy to implement when originally defining objects, it is usually a good ideal to implement the *-side of such relationships (e.g., define referential attributes) and instantiate them properly even if there is no immediate need to navigate them. Then if it turns out a behavior needs some additional attribute data, one can Just Do It without any nasty surprises at test time. The rationale is that the relationship exists in the problem space and its nature is a binary connection whether it is actually used that way to solve the problem in hand or not.

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
}

If there are multiple Cs that are part of an A, don't you need a cMap as well?

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?

The problem here is that anyone wanting to navigate A -> B needs to go through the AController object. I would put the bMap collection in the A instance. Then instantiateA() adds Bs to that collection once A is created.

The interesting question around a Singleton here is: Why would one be adding Parts to a Whole at different times? The point of Singleton is to ensure that only one object actually gets created even though there may be multiple opportunities to create one. That implies that AController and, consequently, A.getInstance() could get called multiple times during the course of the execution. Presumably each time AController would create some set of Bs and Cs to relate to it. But if Bs and Cs are Parts of A, then why weren't they included in the first initialization?

My point is that introducing the notion of Whole/Part tends not to play well with Singleton. It only works if the problem space allows Parts to be added incrementally to A. If not, one needs some other mechanism to /prevent/ invoking AController more than once. If so, that's fine because AController then just adds the new Bs and Cs to the existing A's bMaps. However, this segues to another reason for putting the bMaps in A.

If participants are added incrementally, which is quite common for * relationships, then one usually needs a mechanism to add them /after/ the object is created. Since the collection implements a relationship of the object, it makes sense the object should own the collection and provide the means to add/remove participants.

One could use a factory like AController to instantiate the relationships dynamically, but that is unusual. That's because the context that determines when to /dynamically/ instantiate a new participant is more likely to be known elsewhere. That is, a factory usually encapsulates static rules of instantiation, not dynamic rules that depend on unique solution contexts. [The factory can look at state variables that parameterize dynamic context, but it still needs to know which variables to look at and the developer needs to provide that casting of dynamics into static state variables.]

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?

One typically instantiates a 1:* relationship with a collection object. The object on the 1-side then has a 1:1 relationship with that collection object. IOW,

1 *
[A] -------------- [B]

in the OOA/D is reified at OOP time into

1 1 1 *
[A] -------- [BCollection] ---------- [B]

This may seem like begging the point but [BCollection] can usually be implemented in 3GLs with fundamental data structures like arrays rather than objects. It also allows optimization and reuse by providing specialized library collections. [BCollection] is also hidden as part of A's implementation, regardless of how it is implemented.

The important thing, though, is the [BCollection], however it is implemented, has very narrow semantics. It is essentially a well-defined mathematical construct that is independent of problem semantics (which is why it is so easy to provide library classes and language constructs for it). If the problem space has an entity that would normally act as such a collection and that entity had unique properties relative to the problem in hand, one would have to specify it in the OOA/D as a peer of [A] and [B]. IOW, one would have to explicitly provide the reification rather than just a 1:* relationship.

IOW, the difference lies in separation of problem space and computing environment concerns, semantics, and the difference in level of abstraction between OOA/D and OOP.

[Since I am a translationist, these distinctions probably mean a lot more to me than to you. I can solve the customer's problem in the OOA with 1:* and don't need to think about [BCollection] at all. [BCollection] is the concern of the transformation engine designer, but that is an entirely different union with its own dues. B-)]


*************
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: Passing by reference
    ... It depends upon the reason one is passing the reference. ... instantiate all relationships via a constructor so there will always be ... I naturally think of 'getter' methods as 'knowledge ...
    (comp.object)
  • Re: calling from one workbook the classes and functions in another
    ... having discovered the vb trick recently I'm suddenly a big fan ... > reference to the instantiated class. ... you can't instantiate the class. ... >> Copy your cls into a VB Project for an activex dll. ...
    (microsoft.public.excel.programming)
  • Re: VB6 Common Code for Access, Excel and VB Projects
    ... Instantiate the class as, say, YourClass, then qualify each reference to ... > without a class module included as well. ... >> Compile the code to an ActiveX DLL and add a reference to each VBA/VB ...
    (comp.programming)
  • Re: Opinions on the Law Of Demeter
    ... all that line of code is doing is declaring a reference of type A ... There are only references in Java, no pointers in the C/C++ sense. ... of allowing others to instantiate an object of type A and set it via the ...
    (comp.object)
  • Re: Dynamic inheritance
    ... >I've been reading the Factory and Abstract Factory patterns - and finding ... It seems the problem boils down to where/when to instantiate ... We have an interface named DeviceFactory. ... >Since most devices would be Cisco devices the 'cisco device' subclass would ...
    (comp.object)