Re: Program to interface
From: H. S. Lahman (h.lahman_at_verizon.net)
Date: 03/22/04
- Next message: Shane Mingins: "Re: Second Dimension of Object Oriented Modelling"
- Previous message: Christopher Benson-Manica: "Re: Visitor pattern right for threaded server?"
- In reply to: Eric Kaun: "Re: Program to interface"
- Next in thread: Eric Kaun: "Re: Program to interface"
- Reply: Eric Kaun: "Re: Program to interface"
- Reply: Joe \: "Re: Program to interface"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Mon, 22 Mar 2004 20:22:05 GMT
Responding to Kaun...
> Some things that typically get in the way of proper encapsulation, at least
> for some developers:
>
> 1. Instantiation
>
> The "new" keyword and its ilk are evil, because once it's used in a piece of
> code, you can never change that implementation class. "new" welds you to an
> implementation. The various Factory patterns are remedies for this common
> problem.
I'm not sure what you are driving at here. Are you talking about
physical coupling through things like header files? While that is a
major problem for most OOPLs, I see that as a problem of language design
rather than an intrinsic problem of "new" operators. Unfortunately
physical coupling problems resulting from defining the implementation in
the same place as the public semantics weren't very widely recognized
until mid-'90s.
>
> 2. Implementation instance exposure
>
> If a class offers a getX() method that returns a mutable instance used as
> part of its state representation, you can have a problem. By doing this, a
> class limits its ability to ever change its internal representation, and
> also allows a piece of client code to mutate it using methods not directly
> available in its interface - for example, if a class offers a public List
> getChildren() method, and returns its internal "List children" member, then
> the client can mutate the list at will without going through the class's
> usual addChild() and removeChild() methods.
>
> Solutions include adhering to the Law of Demeter, returning a new mutable
> list, or returning an immutable version of the list.
I see this as a methodological issue. getX() should return a value
rather than a reference. If the knowledge ADT represents something more
complex, that isn't relevant at the class' public level of abstraction
so it should be treated as immutable as if it were a value.
Your example is a gray area of relationship navigation. In theory
relationship navigation is orthogonal to class semantics so its exposure
doesn't matter because it's not part of the class' semantic
implementation. (Automatic code generators treat relationship
navigation much like cross-cutting aspects.) A collection class for,
say, a 1:* relationship is logically distinct from the class "owning"
the collection, even if it is embedded in the "owning" class.
[Automatic code generators deal with this by placing a generic pointer
in the "owning" class. Whoever needs children navigates directly to the
collection class via the "owner's" pointer and invokes the addChild,
removeChild, getChild interface of the collection class. The collection
class has only responsibilities for elementary manipulations of the
collection. This removes the "owner" from knowing anything about how
others access or manipulate the collection.]
My point here is that one can avoid problems with this sort of thing if
one keeps addChild, and RemoveChild out of the "owning" class'
interface. Let the "owning" class just provide a handle to the
collection, Parent.getChildren, that returns the collection class handle
for purposes of relationship navigation.
[BTW, the abstract action languages used for describing behavior in
abstract action languages usually do something like:
childSet = this -> R5 -> R14
where Rn represents a relationship discriminator in the CLass Diagram.
In this case the childSet is the set of objects reached by navigating
the indicated relationship paths. Note that the objects are recovered
without knowing anything about the semantics of the intervening class.
One can't keep things this abstract at the OOPL level, but one can
methodologically write the code as if things were this decoupled.
Note that in this case one can only access the objects. An entirely
different, orthogonal syntax is provided to modify the relationship
collection itself. Something like,
LINK this R5 someInstance
which will get likely get implemented as Collection.Add(someInstance).
This separates the concerns of relationship maintenance from
relationship navigation and indirectly places constraints on When one
can do the maintenance. Again, that OOA/D separation isn't completely
possible in the OOPLs, but one will still be better off emulating it as
much as possible in the construction. That conceptual separation is
what I am looking for in keeping addChild and removeChild out of the
Parent's interface.]
>
> 3. Implementation type exposure
>
> A simple newbie mistake is to type a method as the implementation type - for
> example, as ArrayList rather than List. Simply remedied as long as the
> interface isn't in widespread use. Pity the old Java code stuck with Vector
> methods all over the place... they can never use anything decent internally.
I agree this is a general problem. It tends to show up commonly in
subclassing situations where there are LSP violations. The problem is
that the superclass interface is defined in terms of what the response
to the message is rather than what is happening on the client side. Son
one starts out with:
* chases 1
[Predator] -------------------- [Prey]
+ run()
A
|
+------------+-------+-------+
| | |
[Gazelle] [Rabbit] [Rat]
+ run() + run() + run()
but runs into trouble when one adds:
* chases 1
[Predator] -------------------- [Prey]
+ run()
A
|
+------------+---------------+------------+-------------+
| | | | |
[Gazelle] [Rabbit] [Rat] [Bird] [Stegosaurus]
+ run() + run() + run() + takeFlight() + stomp()
The problem would not exist if the superclass had named the response the
more generic attacked() in the first place.
This problem is a special case of the more generic issue of seeking
invariants in the problem space to encode while relegating the detailed
variations to external data. One of the great advantages of OO
development is the use of abstraction for doing exactly that. Alas, it
is a skill that is difficult to teach.
*************
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
hsl@pathfindermda.com
Pathfinder Solutions -- Put MDA to Work
http://www.pathfindermda.com
(888)-OOA-PATH
- Next message: Shane Mingins: "Re: Second Dimension of Object Oriented Modelling"
- Previous message: Christopher Benson-Manica: "Re: Visitor pattern right for threaded server?"
- In reply to: Eric Kaun: "Re: Program to interface"
- Next in thread: Eric Kaun: "Re: Program to interface"
- Reply: Eric Kaun: "Re: Program to interface"
- Reply: Joe \: "Re: Program to interface"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|