Recipe 2.5.
Creating Subclasses
Problem
You want to
create a class that inherits from an existing class.
Solution
Write a subclass using the extends keyword.
Discussion
There are cases when a new class is a more
specific version of an existing class. The new class may feature
much of the same behavior as the existing class. Rather than
rewriting all the common functionality you can define the new class
so it inherits all the functionality of the existing class. In
relation to one another, the new class is then called a
subclass and the existing class is
called a superclass.
You can define inheritance between classes in the
subclass declaration using the extends keyword, as
follows:
public class Subclass extends Superclass
A subclass can reference any public or protected
properties and methods of the superclass. private
properties and methods are not accessible outside the class, not
even to a subclass.
Inheritance is a powerful technique; however, as
with anything else, it is important that you use inheritance
correctly. Before writing a subclass you need to determine whether
or not the new class actually has a subclass relationship with the
existing class. There are two basic types of relationships that
classes can have: inheritance and composition. You can usually quickly
determine the correct relationship between classes by asking
whether it's an "is a" relationship or a "has a" relationship:
-
"Is a" relationships are often inheritance
relationships. As an example, consider an application that manages
a library's collection.
-
"Has a" relationships are composition
relationships in which a class declares a property. Most classes
use composition. Oftentimes composition can be implemented in such
a way that it achieves the same results as inheritance with greater
flexibility (yet generally requiring more code). For example, a
book is not an author, but it has an author (or authors).
The library has different types of items in the
collection including books and DVDs. Obviously books and DVDs have
different types of data associated with them. Books have page
counts and authors, while DVDs might have running times, actors,
directors, etc. However, you also want to associate certain common
types of data with both books and DVDs. For example, all library
items might have Dewey decimal classifications as well as unique
identification numbers assigned by the library. And every sort of
library item has a title or name. In such a case, it can be
advantageous to define a class that generalizes the commonality of
all library items:
package org.examplelibrary.collection {
public class LibraryItem {
protected var _ddc:String;
protected var _id:String;
protected var _name:String;
public function LibraryItem( ) {}
public function setDdc(value:String):void {
_ddc = value;
}
public function getDdc( ):String {
return _ddc;
}
public function setId(value:String):void {
_id = value;
}
public function getId( ):String {
return _id;
}
public function setName(value:String):void {
_name = value;
}
public function getName( ):String {
return _name;
}
}
}
Then you can say that books and DVDs are both
types of LibraryItem. It would then be appropriate to define
a Book class and a DVD class that are subclasses of
LibraryItem. The Book class might look like the
following:
package org.examplelibrary.collection {
import org.examplelibrary.collection.LibraryItem;
public class Book extends LibraryItem {
private var _authors:Array;
private var _pageCount:uint;
public function Book( ) {}
public function setAuthors(value:Array):void {
_authors = value;
}
public function getAuthors( ):Array {
return _authors;
}
public function setPageCount(value:uint):void {
_pageCount = value;
}
public function getPageCount( ):uint {
return _pageCount;
}
}
}
The "Is a" and "Has a" test is helpful, but not
always definitive in determining the relationship between classes.
Often composition can be used even when inheritance would be
acceptable and appropriate. In such cases the developer might opt
for composition because it offers an advantage or flexibility not
provided by inheritance. Furthermore, there are times when a class
may appear to pass the "Is a" test yet inheritance would not be the
correct relationship. For example, the library application might
allow users to have accounts, and to represent the user, you would
define a User class. The application might differentiate
between types of users; for example, administrator and standard
users. You could define Administrator and
StandardUser classes. In such a case, the classes would
appear to pass the "Is a" test in relation to User. It would
seem to make sense that an Administrator is a User.
However, if you consider the context an Administrator isn't
actually a User, but more appropriately an
Administrator is a role for a User. If possible, it
would be better to define User so it has a role of type
Administrator or StandardUser.
By default it's possible to extend any class.
However you may want to ensure that certain classes are never
subclassed. For this reason you can add the final attribute to the
class declaration, as follows:
final public class Example
|