Scope - do I need two identical classes, each with different scope?

I am trying to understand scope and am getting a little confused. Say
I have a public class "Triangle" with private attributes and public
accessors. This class has attributes of type "Point". Point is
another public class in the same package as Triangle and it, too, has
public accessors. I'd like to allow a program outside the package to
create a Triangle, set the Point attributes, and then call a method in
the Triangle class that performs some calculation and returns a Point.
So far, so good.

The question is, what if I want the Point that is returned to not be
modifiable by this outside program. Do I have to create two Point
classes? Identical except one is public (and would be used to set the
Triangle attributes) and one is default package scope(and would be
returned from the calculation method)?

Advertisements

"ann" <> wrote in message
news:...
>I am trying to understand scope and am getting a little confused. Say
> I have a public class "Triangle" with private attributes and public
> accessors. This class has attributes of type "Point". Point is
> another public class in the same package as Triangle and it, too, has
> public accessors. I'd like to allow a program outside the package to
> create a Triangle, set the Point attributes, and then call a method in
> the Triangle class that performs some calculation and returns a Point.
> So far, so good.
>
> The question is, what if I want the Point that is returned to not be
> modifiable by this outside program. Do I have to create two Point
> classes? Identical except one is public (and would be used to set the
> Triangle attributes) and one is default package scope(and would be
> returned from the calculation method)?

I've asked a few people about their solutions to this type of problem
and haven't yet gotten a design I'm happy with. What I ended up usually
doing is having 3 classes. An abstract base "Point" class, a "MutablePoint"
class which extends Point and a "ImmutablePoint" class which also extends
Point.

Code which don't care whether the Point is mutable or not should use
Point. If they specifically want a mutable point, they use MutablePoint and
similarly for ImmutablePoint.

Sometimes it's also useful to have utility methods to create a
ImmutablePoint from a MutablePoint and vice versa.

Advertisements

Oliver Wong wrote:
> "ann" <> wrote in message
> news:...
>> I am trying to understand scope and am getting a little confused.
>> Say I have a public class "Triangle" with private attributes and
>> public accessors. This class has attributes of type "Point". Point
>> is another public class in the same package as Triangle and it, too,
>> has public accessors. I'd like to allow a program outside the
>> package to create a Triangle, set the Point attributes, and then
>> call a method in the Triangle class that performs some calculation
>> and returns a Point. So far, so good.
>>
>> The question is, what if I want the Point that is returned to not be
>> modifiable by this outside program. Do I have to create two Point
>> classes? Identical except one is public (and would be used to set
>> the Triangle attributes) and one is default package scope(and would
>> be returned from the calculation method)?
>
> I've asked a few people about their solutions to this type of
> problem and haven't yet gotten a design I'm happy with. What I ended
> up usually doing is having 3 classes. An abstract base "Point" class,
> a "MutablePoint" class which extends Point and a "ImmutablePoint"
> class which also extends Point.
>
> Code which don't care whether the Point is mutable or not should
> use Point. If they specifically want a mutable point, they use
> MutablePoint and similarly for ImmutablePoint.
>
> Sometimes it's also useful to have utility methods to create a
> ImmutablePoint from a MutablePoint and vice versa.
>
> I'd love to hear suggestions for better solutions though.

Not necessarily better but your design can be implemented with two classes
(base class immutable, derived class mutable). I guess I'd prefer that
solution because I don't see the need for the third class.

Then there are of course other solutions, for example, you can have a flag
for modifiable state (like Ruby's #freeze and #frozen?) that prevent
calling setters.

I know this rule gets broken oh so often in OO land, but it violates the
fundamental principle that subclasses should embody everything that the
superclass is PLUS some extra features/facets/behaviours/attributes.

If the base class represents something immutable, then all its subclasses
should likewise be. Can you imagine what havoc would be created if Sun
suddenly removed the final keyword from String, thus making it subclassable?
Anyone subclassing String to produce mutable Strings would not get very far.

"jan V" <> wrote in message
news:rlhVe.192195$-ops.be...
>> > I'd love to hear suggestions for better solutions though.
>>
>> Not necessarily better but your design can be implemented with two
>> classes
>> (base class immutable, derived class mutable).
>
> I know this rule gets broken oh so often in OO land, but it violates the
> fundamental principle that subclasses should embody everything that the
> superclass is PLUS some extra features/facets/behaviours/attributes.
>
> If the base class represents something immutable, then all its subclasses
> should likewise be. Can you imagine what havoc would be created if Sun
> suddenly removed the final keyword from String, thus making it
> subclassable?
> Anyone subclassing String to produce mutable Strings would not get very
> far.

Yeah, this is the reason for 3 classes. An ImmutableFoo doesn't have an
IS A relationship with a MutableFoo in either direction. (i.e. it's not the
case that ImmutableFoo IS A MutableFoo, nor a MutableFoo IS A ImmutableFoo).
The only thing they have in common is that they are both Foos.

jan V wrote:
>>> I'd love to hear suggestions for better solutions though.
>>
>> Not necessarily better but your design can be implemented with two
>> classes (base class immutable, derived class mutable).
>
> I know this rule gets broken oh so often in OO land, but it violates
> the fundamental principle that subclasses should embody everything
> that the superclass is PLUS some extra
> features/facets/behaviours/attributes.
>
> If the base class represents something immutable, then all its
> subclasses should likewise be.

Well, it depends. If you say that the base class represents something
with public read methods and protected write methods then sub classes that
have public write methods embody everything of the base class plus an
extra feature. I have seen more fundamental violations of OO principles
that I personally worry more about than this case.
> Can you imagine what havoc would be
> created if Sun suddenly removed the final keyword from String, thus
> making it subclassable? Anyone subclassing String to produce mutable
> Strings would not get very far.

Yes, but if Sun would change this (which won't happen for quite a few
reasons) then they'd likely provide means to modify the internal buffers -
if they wanted String to be mutable. But this is a different story: later
modification of a base class. That's something completely different from
the current issue.

ann wrote:
> I am trying to understand scope and am getting a little confused. Say
> I have a public class "Triangle" with private attributes and public
> accessors. This class has attributes of type "Point". Point is
> another public class in the same package as Triangle and it, too, has
> public accessors. I'd like to allow a program outside the package to
> create a Triangle, set the Point attributes, and then call a method in
> the Triangle class that performs some calculation and returns a Point.
> So far, so good.
>
> The question is, what if I want the Point that is returned to not be
> modifiable by this outside program. Do I have to create two Point
> classes? Identical except one is public (and would be used to set the
> Triangle attributes) and one is default package scope(and would be
> returned from the calculation method)?
>
> Thanks,
> Ann

On a related note, what if, instead of wanting to return a point, I
want to return a Vector of Points. Can I prevent the outside program
from adding or removing Points from the Vector? E.g. Vector v =
triangle.performCalculation(); v.removeAll();

On 12 Sep 2005 08:23:02 -0700, "ann" <> wrote or
quoted :
>The question is, what if I want the Point that is returned to not be
>modifiable by this outside program. Do I have to create two Point
>classes? Identical except one is public (and would be used to set the
>Triangle attributes) and one is default package scope(and would be
>returned from the calculation method)?

One class can be a subset of the other. Unfortunately you can't put
the accessors in a package version then seal them off in a derived
public version. You create a pubic version without accessors and a
second derived version with accessors and a private constructor.
Unfortunately, the derived version must also be public.

People trying to thwart your safety could cast a one to the other, but
at least people would not accidentally get in trouble.
--
Canadian Mind Products, Roedy Green.http://mindprod.com Again taking new Java programming contracts.

> On a related note, what if, instead of wanting to return a point, I
> want to return a Vector of Points. Can I prevent the outside program
> from adding or removing Points from the Vector? E.g. Vector v =
> triangle.performCalculation(); v.removeAll();

With a plain Vector you can't stop the outside world from changing its
content, but if you were to use List as the return type, then you could use
Collections.unmodifiableList(List) to manufacture an ... unmodifiable
(surprise) List with which you could stop the outside program from removing
any Points.

Here is one more approach. You write a class with accessor methods
then have it implement an interface without them, just exposing what
you want. You return objects to your end users only by the interface
reference. The accessors have package scope.
--
Canadian Mind Products, Roedy Green.http://mindprod.com Again taking new Java programming contracts.

Roedy Green wrote:
> Here is one more approach. You write a class with accessor methods
> then have it implement an interface without them, just exposing what
> you want. You return objects to your end users only by the interface
> reference. The accessors have package scope.

That is probably about what I would do, as it makes for looser coupling
between Triangle and Point, and also decouples client applications from
Point altogether. Giving the accessors default/package-private access
does ensure that the client cannot cast the object to Point to get at
the accessors, but I might not go quite that far. If I *never* want
clients to be able to mutate Points then I might do, but on the other
hand I might instead make the whole class package-private and use only
the related interface in the public API. If I ever want clients to be
able to mutate Points in some other context then the accessors need to
be public.

Re: Scope - do I need two identical classes, each with differentscope?

ann wrote:
> I am trying to understand scope and am getting a little confused. Say
> I have a public class "Triangle" with private attributes and public
> accessors. This class has attributes of type "Point". Point is
> another public class in the same package as Triangle and it, too, has
> public accessors. I'd like to allow a program outside the package to
> create a Triangle, set the Point attributes, and then call a method in
> the Triangle class that performs some calculation and returns a Point.
> So far, so good.
>
> The question is, what if I want the Point that is returned to not be
> modifiable by this outside program. Do I have to create two Point
> classes? Identical except one is public (and would be used to set the
> Triangle attributes) and one is default package scope(and would be
> returned from the calculation method)?
>
> Thanks,
> Ann
>

Note that in some cases there is an alternative strategy - return a
clone of the Point, so that you don't have to care of the caller
modifies it.

Share This Page

Welcome to The Coding Forums!

Welcome to the Coding Forums, the place to chat about anything related to programming and coding languages.

Please join our friendly community by clicking the button below - it only takes a few seconds and is totally free. You'll be able to ask questions about coding or chat with the community and help others.
Sign up now!