|
|
|
Sponsored Link •
|
|
Advertisement
|
Bill Venners: So I'm writing a class today and I want to make it easy to clone or copy. What do I do?
Ken Arnold: If you are writing a class today, you have only a few
reasonable interaction patterns. One is to go all the way. You implement the
clone method; you declare it public, without throwing a
CloneNotSupportedException if possible; and you implement
clone. I say "if possible" because you may have to be able to throw
CloneNotSupportedException. The clone method of the
container classes, for example, needs to be able to throw
CloneNotSupportedException, because although the container might be
Cloneable, the objects it references might not be.
There is also a question of deep versus shallow copies. Do you want to copy the
contents, or just the collection that refers to the same underlying objects? A shallow copy
would give you two collections, each of which refers to the same underlying objects,
rather than referring to new underlying objects. If your clone is deep, you might still have
to allow CloneNotSupportedException in your clone
method.
Another approach, which I don't prefer, is to pretend clone and
Cloneable don't exist. However, you can't do that in industrial-strength
classes. In industrial-strength classes, you would either make clone
public, without throwing the exception if you can avoid it. Or you implement
clone so that it will work if invoked, but you let each subclass decide if it
should be public. Or you override clone with something that throws
CloneNotSupportedException; in effect, stating you cannot clone this
even in subclasses. The problem with ignoring clone is that nothing can
stop a subclass from making it public and indirectly invoking your clone
method. Then, if your clone method is inherited from
Object -- in other words, if you have never written one -- and
Object's clone implementation does the wrong thing, the
user will have a corrupt class. It is better to notify users of that with
CloneNotSupportedException. So in industrial-strength classes, I would
pick one of these approaches. There is also this weird, almost surreal, approach where
you can implement Cloneable and not make your clone
method public, but I think you should never do that.
Bill Venners: So what about copy constructors? Do they have a time and place?
Ken Arnold: I am not fond of copy constructors. In fact, I'm not very fond of constructors at all. The problem is that the code that creates the object with a constructor is defining the object's type. In all other operations, the code that uses an object effectively only defines that the object is at least a certain type. Constructors are an exception to that rule. I don't think that exception should exist.
You can also think of it this way: new Foo should turn into an
invocation of a static method that might create a subclass. The static method could look at
the parameters and say: I will create a Foo subclass that is efficient for
these kinds of parameters. At the point where you want a Foo, there are
myriad reasons why the implementer of Foo may know you want a
subclass, but you don't know it. And maybe you shouldn't know it, because next week a
different set of decisions might make sense. The actual class of object that gets created is
an implementation detail. You need something that is at least a Foo. You
should go to the Foo class and say: I need something that is at least what
you are, and here are the initialization parameters. Other languages will do that; of all
things, Perl objects do that. I think this is a better solution. By calling a copy constructor
on Foo, you are asking the Foo class to get a copy of this
object that is at least a Foo, which is not the Foo class's
business.
|
Sponsored Links
|