Re: Program to interface
From: Eric Kaun (ekaun_at_yahoo.com)
Date: 03/22/04
- Next message: Universe: "Re: Object-relational mapping tool"
- Previous message: Shane Mingins: "Re: Second Dimension of Object Oriented Modelling"
- In reply to: H. S. Lahman: "Re: Program to interface"
- Next in thread: H. S. Lahman: "Re: Program to interface"
- Reply: H. S. Lahman: "Re: Program to interface"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Mon, 22 Mar 2004 21:05:16 GMT
"H. S. Lahman" <h.lahman@verizon.net> wrote in message
news:NVH7c.813$fg3.726@nwrdny02.gnilink.net...
> 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.
I was just referring to directly designating the implementation class - and
yes, it is a problem of language design.
> > 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.
Agreed, but this distinction isn't quite as widely understood as it should
be... and is known by manifestations under many different names when it is.
> 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.
Agreed - I should have chosen another.
> 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.
Couldn't agree more - too bad such relational concepts aren't addressed
directly in language design.
> [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.]
A nice summary, though I wonder why the obvious usefulness of something like
this hasn't translated into full relational support in OOs. Though languages
like Alloy show the power of relations in a specification context, I think
they've yet to be fully exploited in implementation languages - at least the
ones with which I'm familiar.
> > 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.
Yes, exactly - a good example.
> 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.
And I think we've yet to see the full exploitation of relations, functions,
and objects in their respective solution domains - a language that can
successfully integrate the power of each, without ending up with spaghetti,
will be interesting. Maybe it's not possible, but I can dream...
- Eric
- Next message: Universe: "Re: Object-relational mapping tool"
- Previous message: Shane Mingins: "Re: Second Dimension of Object Oriented Modelling"
- In reply to: H. S. Lahman: "Re: Program to interface"
- Next in thread: H. S. Lahman: "Re: Program to interface"
- Reply: H. S. Lahman: "Re: Program to interface"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|