From: H. S. Lahman on
Responding to KelvSYC...

> I seem to have trouble building a static factory due to the need to
> build a two-way association:
>
> Right now I'm making some kind of manager class, which, for a static
> factory, takes two maps: one <A, B> and the other <B, C>. The manager
> manages two types of objects: one is a wrapper for A (call it A'), and
> the other is a wrapper for B (call it B'). A and A' have a one-to-one
> relationship, as does B and B'. The manager has a one-to-many
> relationship with A' and B'. (The two input maps are intended to be
> discarded after the manager is built - for example, A and B are
> "primitive input" like strings)

My pushback is: what is "manager" managing? Generally objects like
XxxManager and YyyController will cause OO reviewers to bring out stake,
kindling, and matches. To quote Mellor and Balcer in Executable UML,
"The first rule of partitioning control is that you do not make
controller objects. The second rule of partitioning control is that YOU
DO NOT MAKE CONTROLLER OBJECTS!". Such objects usually represent higher
level nodes in a functional decomposition tree that hard-wire in their
implementations the way other objects collaborate.

I suspect this question is related to your other question, so "manager"
may just be a factory object. If so, that's fine but I would use a more
conventional terminology. B-) BTW, if this the same problem, shouldn't
<B, C> be <A, C>?

> One issue is the need for a two-way relationship: A's and B's are
> associated with their manager, so in order to create the A' for an A
> the manager must first exist. But for the manager to exist it needs
> all of the A's. This is a chicken-and-egg problem that I am unsure of
> how to solve: If X and Y are two classes that are one-to-one with each
> other, and an X and Y object are associated with each other, then
> clearly both objects must be created at the same time. However, this
> can only be done if one object was partially built, the other object
> was built and linked to the partial object, and the partial object was
> completed - which would imply that on one end there would be a public
> interface to change the one-to-one association (making said
> association no-longer one-to-one). How, then do I do this so that
> this does not happen?

I've seen situations where the problem space demanded that referential
integrity be managed explicitly at the OOA/D level, but it is so rare
and was so long ago that I can't even remember a context for a plausible
example. In particular, the X/Y example sounds really fishy. To
instantiate an object all you need are values for its attributes
(including referentials). Having those ready is a precondition on being
able to instantiate it. To instantiate two objects all you need are two
sets of values and having those ready is a precondition to instantiating
them.

So my pushback is that I would bet something else is wrong and this
difficulty is only a symptom. Without knowing anything about the
specific problem it is difficult to speculate on how to resolve the
difficulty. So the following are just some generic possibilities.

The chicken-and-egg problem may only exist within the scope of a factory
method, which is fine. In reality, whenever any object with multiple
unconditional relationships is instantiated there is going to be some
period of time between instructions when referential integrity is not
satisfied simply because instructions require finite time and are
executed sequentially. But that is one reason we encapsulate
instantiation at the method level in OOA/D. That makes it much easier to
ensure that no one accesses the object during that time. (This comes for
free in a synchronous, single-threaded application because only one
procedure can execute at a time; in a concurrent application one has
standard techniques for things like thread safety that work fine so long
as the instantiation scope is a single procedure.)

[Note that it is fair when one has lots of objects and relationships to
instantiate to, say, have a private method to instantiate the objects
and another private method to instantiate their relationships once the
objects are instantiated. So long as those private methods are invoked
with the scope of a single public create() responsibility, one can still
easily manage referential integrity at the OOP level around that public
method scope.]

Note that one way to deal with the <very rare> situation where one needs
multiple create() responsibilities separated in execution time to
complete the instantiation is for all of those responsibilities to be in
the same factory. Then that factory can keep track of "partially"
created objects internally in its private implementation. Then no other
objects in the solution can access them until they are completed (i.e.,
the last create() method instantiates relationships to them). Then the
developer is effectively managing referential integrity in the OOA/D by
ensuring that the multiple create() responsibilities always get invoked
in the right order.

Another possibility is that the relationship may really be conditional.
One tries to avoid such relationships because of the overhead and
fragility, but it isn't always possible.

There is nothing in the multiplicity per se that requires /all/ the
elements on the *-side of a 1:* relationship to be available when the
1-side object is created. When the 1-side object is created one just
needs one object from the *-side. Of course the problem space may demand
that all of them be there (e.g., Whole/Part), but that is pretty
unusual. Even then, there will usually be a point in time in the problem
space where all the necessary information is available. That's because
most customer problem spaces are just as serial as the hardware
computational models.

>
> The other issue is in the construction of A' and B': beyond wrapping A
> and B, I'd like them to have functionality that takes advantage of the
> map - in A' I'd like to get the B's associated with it (determined
> from whether the A is associated with the B), while in B' I'd like to
> test whether an A is associated with this B' (which is done, of
> course, through the manager link) and get the C associated with the
> B' (determined from what C the original B is associated with). The
> issue lies in how this is done, which I am stuck on.

Another basic question: why do you need to "wrap" A and B? Is this a 3GL
dependency management issue, an OOA/D issue, or a problem space issue?

Also, I think things are a bit too abstract here with As and Bs. I am
having a hard time getting my mind around what the real problem is.
Could you be a bit more specific about the problem space,
responsibilities, and collaborations?


*************
There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
hsl(a)pathfindermda.com
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info(a)pathfindermda.com for your copy.
Pathfinder is hiring:
http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH



From: Sasa on
kelvSYC wrote:
> I seem to have trouble building a static factory due to the need to
> build a two-way association:
>
> Right now I'm making some kind of manager class, which, for a static
> factory, takes two maps: one <A, B> and the other <B, C>. The manager
> manages two types of objects: one is a wrapper for A (call it A'), and
> the other is a wrapper for B (call it B'). A and A' have a one-to-one
> relationship, as does B and B'. The manager has a one-to-many
> relationship with A' and B'. (The two input maps are intended to be
> discarded after the manager is built - for example, A and B are
> "primitive input" like strings)

>
> One issue is the need for a two-way relationship: A's and B's are
> associated with their manager, so in order to create the A' for an A
> the manager must first exist. But for the manager to exist it needs
> all of the A's. This is a chicken-and-egg problem that I am unsure of
> how to solve: If X and Y are two classes that are one-to-one with each
> other, and an X and Y object are associated with each other, then
> clearly both objects must be created at the same time. However, this

Almost - you cannot create both at the same time, you create first one
then second, then connect them.

One way to do this is to construct Y in the constructor of X.

Alternatively, you could have some other factory class/method which
creates both and connects them, but then both classes must have setters
for instances of X/Y.

> can only be done if one object was partially built, the other object
> was built and linked to the partial object, and the partial object was
> completed - which would imply that on one end there would be a public
> interface to change the one-to-one association (making said
> association no-longer one-to-one). How, then do I do this so that
> this does not happen?

If you want to make one to one association imutable, you might consider
the constructor solution (in the constructor of X you create Y providing
it with the this pointer).

If this is not possible, you might used the alternative I suggested, but
somehow hide the public interface for changing association. Ideally,
only the factory class should be able to use this service to setup the
association. You might do this by moving both classes to separate
package, make some package only visible methods in both classes which
allow you to setup association after the instances have been created and
make public factory method.
This is not elegant, but it shields you from external users changing the
association once it is established.

> The other issue is in the construction of A' and B': beyond wrapping A
> and B, I'd like them to have functionality that takes advantage of the
> map - in A' I'd like to get the B's associated with it (determined
> from whether the A is associated with the B), while in B' I'd like to
> test whether an A is associated with this B' (which is done, of
> course, through the manager link) and get the C associated with the
> B' (determined from what C the original B is associated with). The
> issue lies in how this is done, which I am stuck on.

What is a problem here?
If you have bidirectional association between manager and A' and manager
and B' - both A' and B' objects can pass such queries to manager.



I'll try to rephrase your problem to describe how I understood it, based
on your original post and response to HSL:

1. Manager holds associations to instances of other classes, and some
other data about A' such as number of instances.

2. Hence at each moment the Manager must know about each existing A'

3. And A' must know about manager to ask him some questions (such as -
which are my B's).

Did I understand that correctly?

Sasa
From: H. S. Lahman on
Responding to KelvSYC...

>>>Right now I'm making some kind of manager class, which, for a static
>>>factory, takes two maps: one <A, B> and the other <B, C>. The manager
>>>manages two types of objects: one is a wrapper for A (call it A'), and
>>>the other is a wrapper for B (call it B'). A and A' have a one-to-one
>>>relationship, as does B and B'. The manager has a one-to-many
>>>relationship with A' and B'. (The two input maps are intended to be
>>>discarded after the manager is built - for example, A and B are
>>>"primitive input" like strings)
>>
>>My pushback is: what is "manager" managing? Generally objects like
>>XxxManager and YyyController will cause OO reviewers to bring out stake,
>>kindling, and matches. To quote Mellor and Balcer in Executable UML,
>>"The first rule of partitioning control is that you do not make
>>controller objects. The second rule of partitioning control is that YOU
>>DO NOT MAKE CONTROLLER OBJECTS!". Such objects usually represent higher
>>level nodes in a functional decomposition tree that hard-wire in their
>>implementations the way other objects collaborate.
>
>
> The idea is that the <A, B> map defines a partition over the A entries
> within (so A is many-to-one with B). The <B, C> map is a simple
> mapping (which we can assume to be one-to-one). Essentially, this is
> managing the composition of two maps with a twist.

I'm still pushing back that if A, B, and C are objects, then those
"maps" implement that relationship and would be owned by A rather than
some other object. [But A and B do not seem to be objects below, so they
wouldn't have relationships at all.]

Alas, I am sorry but I really don't see the relevance of the following
example to the problem you have been describing. The mapping you
describe (e.g., A' and B') seem superfluous to me. I inserted comments
on some of the things that bother me. But I think the real problem is
that I would have abstracted the problem space in a much different
manner, as I indicate below.

>
> To think of this, suppose A is a string, representing specific coinage
> (eg. "Canadian penny", "Canadian nickel", "US Silver Dollar", etc). B
> is also a string, representing the currency the coinage belongs to
> (eg. "CAD", "USD", "EUR", etc). In essence, A and B both represent
> raw data, to be constructed into proper objects. C represents a class

Then A and B aren't objects. What object is being constructed from them?
That is the one whose relationships one needs to worry about.

Also, it seems to me A and B are redundant; the coinage already defines
the currency. [Even if they are arbitrary codes, one can still have a
table lookup to figure out the currency and that lookup table can be
initialized from external configuration data. IOW, the mapping to
currency that B provides can be provided without dedicated problem space
objects.]

> of delegate objects (previously constructed), converting quantities of
> B to a common fixed currency. Continuing along, B' then would

So C needs to convert one currency to another, which is a collaboration
rather than an instantiation. I would assume C collaborates with
whatever object one creates from A and B.

> represent some currency object, where it uses C to convert to another
> currency. A' then, would represent some amount of in currency B'.

This where things really break down for me. Why do you need B'? Why
can't C do its thing and convert the currency in a collaboration?

> What I want to do, then, would be a way to manage A' (the coinage
> objects) and B' (the currency objects) given the two maps - hence the
> manager (which we assume is immutable). This manager would then be
> used to get all the A' (coins) and B' (currencies) for any number of
> purposes (for example, given an <A', int> map, determine how much of
> that common fixed currency you have). The reason why the manager
> itself is not a singleton is that, for example, you have a manager for
> "present-day currency conversion" and another for "1920 currency
> conversion".

What this example suggests to me is that one has something like the
following in the problem space:

[ConversionSpec]
+ multiplier
+ timePeriod
| 0..1
|
| R1
|
| specifies conversion of
| 0..*
[Coinage]
+ denomination
+ quantity
+ currency
+ convert()
| *
|
| R2
|
| converted to
| 1
[CommonCurrency]
+ amount

The [Coinage] objects capture the raw data and an object is presumably
instantiated from some external message data packet (e.g., from a UI).
If the data arrives in the form of {coinID, number}, then the factory
that creates a Coinage would do a table lookup on coinID to get
denomination and currency values.

A Coinage is assigned a ConversionSpec (R1) based upon the currency and
desired time period. The R1 relationship is conditional because it
cannot be instantiated until one knows the desired time period, which I
assume is provided later (but necessarily before convert() is invoked).
(The R1 relationship is conditional on the *-side because only one such
specification is associated with a Coinage, presumably at most one
Coinage is alive at a time, and the time period may not be known when
Coinage is created.) IOW, R1 is fully dynamic in its instantiation.

[ConversionSpec] contains a conversion factor to the base currency for a
particular time period. The [ConversionSpec] objects are dumb data
holders that can be instantiated at startup from external configuration
data for conversion rates. The convert() behavior employs the
ConversionSpec multiplier and denomination to compute the amount of the
designated common currency. (The convert() method could create a
CommonCurrency since it is trivial, in which case R2 is also conditional
on the 1-side.)

The only trickiness here for instantiation is that the R1 relationship
needs to be instantiated dynamically based on the the value of
Coinage.currency and the desired time period. If the desired time period
is not known when Coinage is instantiated, then R1 is necessarily
conditional and the developer must ensure that it is instantiated before
convert() is invoked.

[Note that convert() could create the CommonCurrency object since it
seems to be trivial. But then R2 needs to be conditional on the 1-side
and it probably has 1 multiplicity on the Coinage side.]

>>The chicken-and-egg problem may only exist within the scope of a factory
>>method, which is fine. In reality, whenever any object with multiple
>>unconditional relationships is instantiated there is going to be some
>>period of time between instructions when referential integrity is not
>>satisfied simply because instructions require finite time and are
>>executed sequentially. But that is one reason we encapsulate
>>instantiation at the method level in OOA/D. That makes it much easier to
>>ensure that no one accesses the object during that time. (This comes for
>>free in a synchronous, single-threaded application because only one
>>procedure can execute at a time; in a concurrent application one has
>>standard techniques for things like thread safety that work fine so long
>>as the instantiation scope is a single procedure.)
>>
>>[Note that it is fair when one has lots of objects and relationships to
>>instantiate to, say, have a private method to instantiate the objects
>>and another private method to instantiate their relationships once the
>>objects are instantiated. So long as those private methods are invoked
>>with the scope of a single public create() responsibility, one can still
>>easily manage referential integrity at the OOP level around that public
>>method scope.]
>
>
> What of the objects themselves? In the context of a static factory,
> you'd need a public method on the objects to set the relationships,
> but which needs to be somewhat "hidden" so that the relationships
> cannot be altered once instantiated (like ugly default-access in
> Java). Based on this, I have an idea:

Unfortunately I can't respond to that because I think static factories,
"managers", Singleton, and external maps are overkill, especially after
the example above. My pushback is that I think the problem space may
need to be abstracted in a simpler fashion.

>>>The other issue is in the construction of A' and B': beyond wrapping A
>>>and B, I'd like them to have functionality that takes advantage of the
>>>map - in A' I'd like to get the B's associated with it (determined
>>>from whether the A is associated with the B), while in B' I'd like to
>>>test whether an A is associated with this B' (which is done, of
>>>course, through the manager link) and get the C associated with the
>>>B' (determined from what C the original B is associated with). The
>>>issue lies in how this is done, which I am stuck on.
>>
>>Another basic question: why do you need to "wrap" A and B? Is this a 3GL
>>dependency management issue, an OOA/D issue, or a problem space issue?
>
>
> As I've put it above, if A and B represent some raw data, then the
> wrapping is necessary to create proper objects out of them.

That was my point above about A and B not being objects. They are simply
inputs to some object, presumably some sort of factory, that creates
some other object. If so, there aren't any relationships to them so one
doesn't need to "wrap" them with interfaces; they are just data.

What I suspect is happening here is that A and B /are/ dumb data holder
objects in the form of descriptors (e.g., {number, coinID}) that you are
getting from some place else. If so, they either correspond to [Coinage]
in my model above or a Coinage object can be created from them. But I
don't think that instantiation of [Coinage] would present any special
problems insofar as its relationships are concerned.


*************
There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
hsl(a)pathfindermda.com
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info(a)pathfindermda.com for your copy.
Pathfinder is hiring:
http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH