150 likes | 272 Views
This lecture discusses the Decorator Pattern in Java, exemplified with a SongLog application. The primary goal is to create an object representing a song log that records songs played along with the ability to query when they were last played. The lecture details the pattern's implementation, emphasizing the advantages of adding functionality without subclassing. It explains how to extend interfaces for decorating classes, create decorators, and manage the decorator's encapsulation. This approach provides flexibility in software design by avoiding the pitfalls of deep inheritance hierarchies.
E N D
Decorator COMP 401, Spring 2012 Lecture 18 3/21/2013
A motivating example: SongLog • Goal: • Create an object to represent a song “log” (i.e., record of what songs were played) • Provide ability to answer queries about songs played. • Design: • void recordInLog(SongInterfaces) • void recordInLog(SongInterfaces, Date time) • Date lastPlayed(SongInterfaces) COMP 401 :: Spring 2012
Date • Java’s class for dealing with Date • Represents a point in time down to millisecond precision. • Separate classes for formatting and calendar operations. • Calendar • DateFormat • Provides a number of pre-defined formats • SimpleDateFormat • Allows you to construct customized formats • See Date tutorial on Oracle site for more. COMP 401 :: Spring 2012
SongLog version 1 • lec18.v1 • Strategy: • Maintain two array lists • One for songs • One for dates COMP 401 :: Spring 2012
SongLog v1 critique • It works, but not as clean as it could be. • Why? COMP 401 :: Spring 2012
Decorator Pattern • Useful when you want to add additional state or functionality to a class without formally subclassing. • When might that be? • Additional state/functionality is auxiliary to object’s main purpose. • Additional state/functionality is local to a collection or some other class encapsulating the object. • SongLog for example. • As a workaround for multiple inheritance • Want to build up an object with subsets of different functionality. • Decorator pattern is a form of delegation. COMP 401 :: Spring 2012
Decorator Pattern Recipe • Setting up: • Start with original interface. • If decorating a class without an interface, refactor original class to have an interface. • In our example: • Song (this is the interface) • SongImpl COMP 401 :: Spring 2012
Decorator Pattern Recipe • Step 1: • Extend interface, declaring additional functionality. • In our example: • LoggedSong • Date getDate(); COMP 401 :: Spring 2012
Decorate Pattern Recipe • Step 2: • Create class that implements decorated interface. • Provide constructor that takes an object of the original (i.e., undecorated) interface type and possibly any additional state information needed for decorated behavior. • Delegate original interface methods to encapsulated object. • Provide implementations for decorated behavior. • In our example: • LoggedSongImpl • public LoggedSongImpl(Song s, Date d) • Date getDate() COMP 401 :: Spring 2012
SongLog v2 • This version decorates the songs as logged songs and then stores them. COMP 401 :: Spring 2012
Decorator Avoids Subclassing • Decorator applies to interfaces (not classes). • Caveat: as I am teaching it here. • It’s the interface that is being decorated. • Subinterfacing is distinct from subclassing • Both are types of inheritance, but not the same • This is why we encounter statements like: • Decorators provide a flexible alternative to subclassing for extending functionality. • See Decorator in Java tutorial from Abhi On Java link in readings. • This is why we needed Song to be an interface with an accompanying class (i.e., SongImpl) implementation. COMP 401 :: Spring 2012
Decorator Illustrated interface I { void do_something(); } class C implements I { void do_something() { ... } } class DC implements DI { private I wrapped_i; public (I i_obj) { wrapped_i = i_obj; } void do_something() { wrapped_i.do_something(); } void do_more() { ... } } interface DI extends I { void do_more(); } COMP 401 :: Spring 2012
Unwrapping the Decorator • When you decorate an existing object, you are creating a new object. • Existing object is inside. • Might need to have the ability to “undecorate” the object. • For example, if we need to give it back to someone who expects the original. • lec18.v3 COMP 401 :: Spring 2012
Undecorating • Provide method to get back original in decorated interface. interface I { void do_something(); } class C implements I { void do_something() { ... } } class DC implements DI { private I wrapped_i; public (I i_obj) { wrapped_i = i_obj; } public I getWrapped() { wrapped_i; } void do_something() { wrapped_i.do_something(); } void do_more() { ... } } interface DI extends I { void do_more(); I getWrapped(); } COMP 401 :: Spring 2012
Assignment 5 • You can add new state to piece subclasses if you need / want to. • But you shouldn’t have to. • You can create new methods in the parent class as helpers for your subclasses. • Be sure to mark as “protected” to provide access. • HINT: This might be useful for checking line of sight path between start and finish.