Re: Separation of API and implementation



Responding to Hforco2...

As a practical matter this would be further enforced at the OOA/D level
by not passing 'y' as a reference to B::foo at all. Instead one would
instantiate a relationship between the B object and 'y'. Whoever
instantiates that relationship (by assigning the reference) would
encapsulate the rule that 'y' can only be a Yb. Then the B object just
collaborates with whoever is on the other end of the relationship
regardless of what interface is used and everything will Just Work. The
main purpose of relationships in the OO paradigm is to limit
participation in collaborations so we should take advantage of that.



Do you have a simple example of this - I don't fully grasp what you
mean by creating a relationship as opposed to a collaboration.

In an OO context a collaboration means that a message passes between two objects. That message will usually trigger some response in the receiver. Relationships (UML associations) define the static structure that limits collaboration. Instantiating a relationship constrains Who may participate in the collaboration. Sending a message initiates a collaboration (i.e., defines When the response should happen) and we address the message by navigating an existing relationship.

Passing an object reference essentially creates a temporary relationship between the passed object reference and the receiver whose scope is the receiving method. That's not a good idea because it requires the caller to know exactly which object the receiver needs to collaborate with. IOW, it creates a dependency in the caller's implementation on the context of how the receiver collaborates with other objects, which is often none of the caller's business.

Your basic model is:

[Y]
A
+ doIt()
| R1
+-----+------+
| |
[A] [B]
+ foo()
| 1
| accesses
|
| R2
|
| 1
[Client]

Here some Client accesses B::foo. The problem is that B::foo needs to access Y::doIt(), in an object other than itself. If Client passes the Y object to B::foo, the Client is temporarily instantiating a relationship between B and some other Y. If B could access any Y, then the association would look like:

1 accesses
[Y] -----------------+
+ doIt() |
A |
| R1 | R3
+-----+------+ |
| | 1 |
[A] [B] ----------+
+ foo()
| 1
| accesses
|
| R2
|
| 1
[Client]

In that case the C++ code (I don't do Java) would look like:

class Y
{
public:
virtual void doIt();
....
}

class A : Y
{
....
}

class B : Y
{
private:
Y* myY; // implement R3
public:
void foo();
void setR3 (Y* y) {myY = y;}; // instantiate R3
....
}

B::foo()
{
...
myY->doIt(); // navigate R3
...
}

class Client
{
private:
B* myB; // implement R2
public:
void doSomething():
void setR2 (B* b) {myB = b;}; //instantiate R2
....
}

void Client::doSomething()
{
...
myB->foo(); // navigate R2 to collaborate
...
}

Note that this assumes somebody else has already set myY and myB. When B::foo() navigates the R3 association, it takes whatever implementation of Y::doIt() the object at the end of the association has. This is basic polymorphic dispatch. Since myY is a Y, the compiler will allow the object to be a member for either [A] or [B] and B should be indifferent to this.

Your problem is that B is not indifferent to the implementation of Y::doIt(); it can only collaborate with another [B] object's implementation, which greatly constrains participation in the collaboration. That means the model and the implementation of R3 change:

[Y]
+ doIt()
A
| R1
+-----+----------------+
| |
| accesses 1 | 1
[A] +-------- [B] ----------+
| + foo() |
| | 1 | R3
| | accesses |
| +------------+
| R2
|
| 1
[Client]


class Y
{
public:
virtual void doIt();
....
}

class A : Y
{
....
}

class B : Y
{
private:
B* myB; // implement R3
public:
void foo();
void setR3 (B* b) {myB = b;}; // instantiate R3
....
}

B::foo()
{
...
myY->doIt(); // navigate R3
...
}

class Client
{
private:
B* myB; // implement R2
public:
void doSomething():
void setR2 (B* b) {myB = b;}; //instantiate R2
....
}

void Client::doSomething()
{
...
myB->foo(); // navigate R2 to collaborate
...
}

Now the R3 association can only be with another member of [B] that correctly implements the doIt() behavior and this is the only thing that changes. When whoever instantiates the R3 association provides a reference when invoking B::setR3, that reference must be a B or else the compiler will have a kitten. So one has a built-in validation that whoever instantiates the R3 relationship does it correctly.

In either case there is value in not passing 'y' to B::foo(). Instantiating the pointer reference in [B] allows one to separate the concerns of deciding Who should participate from the concerns of When they should participate in a collaboration. Even if the Client is logically the one to instantiate the relationship today, that may not be the case tomorrow.


*************
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: Getting a reference to an object instantiated by doClick()
    ... instantiates it, post this stripped-down code. ... the action listener creates the dialog. ... > a reference to that dialog. ... The API says that doClick() is a method from ...
    (comp.lang.java.gui)
  • Re: Getting a reference to an object instantiated by doClick()
    ... me into my logic for handling a 'Change Preferences' click in the GUI's ... instantiation of my Preferences dialog and a reference to that dialog. ... the doClick() caused me to go to the 'Change Preferences' logic. ... > instantiates it, post this stripped-down code. ...
    (comp.lang.java.gui)
  • Re: Class in separate add in?
    ... You can add a property to the module that instantiates and returns a ... Eg the addin called XXX has a class called clsPBar; ... Then any module with a reference to the addin can use ...
    (microsoft.public.word.vba.general)
  • Re: Design help...an explosion of interfaces......
    ... Whoever instantiates the direct subclass ... >>the subclass is still transparent to both the client and whoever ...
    (comp.object)
  • Re: Is object created?
    ... closed - I detected the error and shut down the VB app. ... > be instantiated whenever you reference it. ... > will always evaluate to False, because the reference to oEmp instantiates ...
    (microsoft.public.vb.general.discussion)