Monday, September 08, 2003

More on final

More from the PragProg list:
>From: Ged Byrne
>In 'Effective Java' Bloch goes to the other extreme.
>
>Item 15 is "Design and document for inheritance or
>else prohibit it." Basically, every class should be
>Final unless you have specifically designed for
>inheritance.
>
>http://java.sun.com/docs/books/effective/toc.html
>
>His argument is that inheritance provides an
>additional interface to your objects. If you allow
>somebody to extend your objects in a way that you
>never imagined, then you are forced to either always
>support that unintended use for the entire life of the
>object or upset users of your interface when things
>change.

I think making your objects all final is going way to far. I generally make
my internal data local to my class, but expose the methods for accessing to
be protected. I think people should write lots of little methods and
override where you need to in subclassing. I generally take a more
responsiblity driven approach to my design. I tend to think of the interface
before the internal data implementation. If you provide accessors for your
internal structure and make sure that only subclasses have access. I think
you should only make things public that you must. But, subclasses should
have access to all of its superclasses' methods and not their instance
variables. This forces subclasses to use the accessors. If you change this
aspect, generally you can deprecate the accessors and put in an
implementation in the method that wraps the internals if that makes sense.
Generally, I use a lot of interfaces whenever I can and avoid primitive
types. I also find that staying true to the law of demeter also reduces the
exposure of internals changing on the subclasses.

>One of the promises of OO is that behind the interface
>you can change all of the internal workings. I might
>start off by writing an object that keeps some data in
>a persisted array. As the objects grows the array is
>too small and become a problem, so it is replaced by a
>database table.

You see I would make the persisted array an object in of itself and expose
it via an interface. If I needed to change the implementation, then I would
be changing the persisted array and not the class that's holding on to it.

>If you OO has a tight interface, then you make the
>change to just this one object and your done.

Exactly!

>If, on the other hand, your object exposed the
>internal array to subclasses and these subclasses use
>the array directly then when you update the object you
>either have to write a pseudo proxy that will behave
>just like the array to subclasses or rewrite all the
>subclasses.

Yes. My point would be to make sure that the persisted array has its on
interface. I use interfaces a lot in Java because I only care if an object
implements a protocol and not what it is per se. I just care that I get
something that implements that interface and I don't care how it does it
behind the scenes. I find interfaces and keeping with the law of demeter
helps my designs to be more flexible in this regard.

If truth be told, My inheritence heirarchies are generally very shallow.
They rarely get deeper than 3. I find polymorphism to be a much more useful
abstraction in terms of making my objects less coupled. Also, my super
classes generally tend to be more of the template pattern where the
subclasses are just providing different functionality at different points
and interacts very little with the super class.

>So, by this argument (don't know if I entirely agree)
>if you expose your objects internals then you are
>saying 'the internal implementation is perfect. I
>will never have to change it, so do whatever you want
>with it.'

I don't view subclassing as "exposing your internals", but I can see where
you're going with it. I think a subclass is still behind the lines. I think
subclass takes on the responsibility of if the superclass changes, then I
must change as well. I do not think it's up to the super class owner to make
sure his code works with all possible subclasses. I think it's nice for the
super class owner to provide upgrade paths via deprecating methods and
putting in workarounds, but not necessary. I have not found the changing
super class to a problem on any system that I've worked on. Good design
always makes things easier.

No comments: