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

A

ann

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
 
O

Oliver Wong

ann said:
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.

- Oliver
 
R

Robert Klemme

Oliver said:
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.

Kind regards

robert
 
J

jan V

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.
 
O

Oliver Wong

jan V said:
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.

- Oliver
 
R

Robert Klemme

jan said:
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.

Kind regards

robert
 
A

ann

Thanks Oliver and Robert for your suggestions. I think I will try the
3 method route.

Sincerely,
Ann
 
A

ann

ann said:
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();

Ann
 
R

Roedy Green

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.
 
J

jan V

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.
 
R

Roedy Green

I'd love to hear suggestions for better solutions though.

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.
 
J

John C. Bollinger

[Re: class Triangle, containing mutable Points, providing immutable
views of those Points]

Roedy said:
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.
 
P

Patricia Shanahan

ann said:
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.

Patricia
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,733
Messages
2,569,440
Members
44,832
Latest member
GlennSmall

Latest Threads

Top