Section 5.3. Abstract Classes


5.3. Abstract Classes

Sometimes when you are using generalization to declare a nice, reusable, generic class, you will not be able to implement all of the behavior that is needed by the general class. If you are implementing a Store class to store and retrieve the CMS's articles, as shown in Figure 5-11, you might want to indicate that exactly how a Store stores and retrieves the articles is not known at this point and should be left to subclasses to decide.

Figure 5-11. Using regular operations, the Store class needs to know how to store and retrieve a collection of articles


To indicate that the implementation of the store(..) and retrieve(..) operations is to be left to subclasses by declaring those operations as abstract, write their signatures in italics, as shown in Figure 5-12.

Figure 5-12. The store(..) and retrieve(..) operations do not now need to be implemented by the Store class


An abstract operation does not contain a method implementation and is really a placeholder that states, "I am leaving the implementation of this behavior to my subclasses." If any part of a class is declared abstract, then the class itself also needs to be declared as abstract by writing its name in italics, as shown in Figure 5-13.

Figure 5-13. The complete abstract Store class


Now that the store(..) and retrieve(..) operations on the Store class are declared as abstract, they do not have to have any methods implemented, as shown in Example 5-4.

Example 5-4. The problem of what code to put in the implementation of the play( )operation is solved by declaring the operation and the surrounding class as abstract

 public abstract class Store {    public abstract void store(Article[] articles);    public abstract Article[] retrieve(  ); } 

An abstract class cannot be instantiated into an object because it has pieces missing. The Store class might implement the store(..) and retrieve(..) operations but because it is abstract, children who inherit from the Store class will have to implement or declare abstract the Store class's abstract operations, as shown in Figure 5-14.

Figure 5-14. The BlogStore class inherits from the abstract Store class and implements the store(..) and retrieve(..) operations; classes that completely implement all of the abstract operations inherited from their parents are sometimes referred to as "concrete"


By becoming abstract, the Store class has delayed the implementation of the store(..) and retrieve(..) operations until a subclass has enough information to implement them. The BlogStore class can implement the Store class's abstract operations because it knows how to store away a blog, as shown in Example 5-5.

Example 5-5. The BlogStore class completes the abstract parts of the Store class

 public abstract class Store {      public abstract void store(Article[] articles);    public abstract Article[] retrieve(  ); }   public class BlogStore {      public void store(Article[] articles) {       // Store away the blog entries here ...    }       public Article[] retrieve(  ) {       // Retrieve and return the stored blog entries here...    } } 

An abstract class cannot be instantiated as an object because there are parts of the class definition missing: the abstract parts. Child classes of the abstract class can be instantiated as objects if they complete all of the abstract parts missing from the parent, thus becoming a concrete class, as shown in Example 5-6.

Example 5-6. You can create objects of non-abstract classes, and any class not declared as abstract needs to implement any abstract behavior it may have inherited

 public abstract class Store {      public abstract void store(Article[] articles);    public abstract Article[] retrieve(  ); }   public class BlogStore {      public void store(Article[] articles) {       // Store away the blog entries here ...    }       public Article[] retrieve(  ) {       // Retrieve and return the stored blog entries here...    } } public class MainApplication {      public static void main(String[] args) {         // Creating an object instance of the BlogStore class.       // This is totally fine since the BlogStore class is not abstract.       BlogStore store = new BlogStore(  );       blogStore.store(new Article[]{new BlogEntry(  )});       Article[] articlesInBlog = blogStore.retrieve(  );         // Problem! It doesn't make sense to create an object of       // an abstract class because the implementations of the       // abstract pieces are missing!       Store store = new Store(  ); // Compilation error here!    } } 

Abstract classes are a very powerful mechanism that enable you to define common behavior and attributes, but they leave some aspects of how a class will work to more concrete subclasses. A great example of where abstract classes and interfaces are used is when defining the generic roles and behavior that make up design patterns. However, to implement an abstract class, you have to use inheritance; therefore, you need to be aware of all the baggage that comes with the strong and tightly coupling generalization relationship.

See the "Generalization (Otherwise Known as Inheritance)" section earlier in this chapter for more information on the trials and tribulations of using generalization. For more on design patterns and how they make good use of abstract classes, check out the definitive book on the subject Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley).




Learning UML 2.0
Learning UML 2.0
ISBN: 0596009828
EAN: 2147483647
Year: 2007
Pages: 175

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net