150 likes | 164 Views
More Patterns. CS 124. More Basic Patterns. Patterns you’ve already seen (without knowing it) Observer / Listener Wrapper Composite Decorator / Filter Patterns you might be using already, or might want to use Strategy Facade Command. Observer / Listener. Idea:
E N D
More Patterns CS 124
More Basic Patterns • Patterns you’ve already seen (without knowing it) • Observer / Listener • Wrapper • Composite • Decorator / Filter • Patterns you might be using already, or might want to use • Strategy • Facade • Command
Observer / Listener • Idea: • Allow “Listeners” to be added to an object • When “something happens” to that object, a certain method is called on each Listener • Benefits: • Event-driven programming program in terms of reactions to events (good for interactive programs) • Allows you to place event-handling logic in a separate class • Allows you to have multiple listeners – no limit to what you can do when an “event” happens • Example: • in AWT/Swing, you handle events by adding Listeners • In Java, there is the also the Observable class and Observer interface • In real life, Publish-Subscribe or “Push” services • e.g., you get an email if there is an interesting news topic
<<interface>> Listener EventGenerator • When a relevant event in the EventGenerator occurs, it will invoke the appropriate event method on all the listeners event1Method() event2Method() … -listeners:List +addListener(Listener) added ListenerImpl
Wrapper • Idea: • Hide an object in another object • Interact only with the outer object • Benefits: • Allows you to control access to original object • Users can’t call the method of the original object directly • You can only allow certain methods • You can change the method calls (similar to Adapter) • You can add / modify functionality • Hide detail of original object • Allows you to change implementation later • Example: • InventoryList contains a Vector, but you don’t interact with the Vector directly. InventoryList provides the getProduct() method, which internally calls the Vector, but it casts the result to Product, so the user gets a product type and doesn’t need to do cast himself
Immutability / ReadOnly Wrapper • Using a Wrapper to hide the setXXX() methods renders the enclosed object unmodifiable/immutable Immutable Address Address +getAddress() : String +setAddress(String) +ImmutableAddress (Address) +getAddress() : String
Decorator • Idea: • “Chain” objects together • Objects can add functionality to other objects (also hide) • Chain functionality • (Similar to Wrapper, but allows infinite chain of wrapping.) • Benefits: • Can be used to add or enhance functionality • e.g., PrintStream adds print and println methods to simple Stream objects, ObjectInputStream adds readObject method. • e.g., BufferedInputStream performs buffering for you • Decorators can decorate different classes • e.g., ObjectInputStream can be used with FileInputStream, the InputStream of Socket, ByteArrayInputStream, etc. • Example: • in Files, BufferedReader, PrintStream, ObjectInputStream, etc. are Decorators that can be applied to basic Readers / InputStreams
Hmm … they look the same • Adapter, Wrapper, Decorator have very similar implementations • generally they are about putting an object in another object with minor variations • however, they vary mainly in their intent • why they are putting the object in another object in the first place • it is the intent that determines which pattern you are actually using not the implementation
Open-Close Principle • A principle that is followed by many design patterns • Open to Extension • Closed to Modification • The basic idea is that code should be open for adding new behaviour using composition or inheritance but closed to code modification • prevents adding new bugs to old working code • This can be seen with the Adapter and Decorator • behaviour is added by using an instance within the class
Composite • Idea: • Container contains Components • Container is-a Component itself • Benefits: • A container can contain another container, ad infinitum • Easier to manage complexity • you only need to see and handle the top-level containers • Containers take care of handling their components • Examples: • in AWT/Swing, you can add Panels to panels. This allows infinite nesting of GUI elements • In your paint-a-shape programs, you can make a Shape class that contains other Shapes
Command • Idea: • Encapsulate things-you-can-do into Command objects • Fields specify details • Kind of command can be a field (int or String) • Or, you can use polymorphism • Write an “Executor” class that can take individual Command objects and perform them accordingly • use a switch or if-else chain if command type is int or String • if you’re using polymorphism, you can call execute() method on Command, or use Visitor pattern (more advanced) • Benefits: • Allows you to treat commands/operations as objects place them on queues, send them over the network, undo/redo queues/stacks • Examples: • In your games, you can send Move objects over the network to tell the server (or the other player) what kind of move the player wants to make
Strategy • Idea: • Put changeable logic in a separate class • Pass an instance of that class into the function or object that uses the changeable logic • Benefits: • “Template” code for the main algorithm remains the same and doesn’t need to be recompiled • Change logic by simply giving a different Strategy object • Examples: • Arrays.sort( Object[] array, Comparator c ) static utility method • Comparator is an interface that has compare( Object a, Object b ) which returns whether a > b, a equals b, or a < b. • To use, implement the Comparator interface, and define compare method appropriately. Then, pass instance of your new class as parameter in Arrays.sort • You can use inner classes to define the class on-the-spot
Facade • Idea: • Create a class that acts as a “front” to another class or system • Provide methods that you or your users need to use • Translate these to method calls using the other class or system • Benefits: • Simplify programming interface for you and users of your code • Enable you to use other “messier” code internally, without making it visible to programmers • Allows you to swap back-end code in the future • Examples: • For your network programs, instead of writing directly to the OutputStream, create a class Communicator that has methods for sending just the kinds of data you need. • e.g., sendGameMove( GameMove gm ) or receiveGameMove() • Then, you can hide whether you are using Strings, or ObjectOutputStream, etc. • Also, now only one class can write data to the stream. Thus, if you get an error, you know where to look
Combinations • Usually Design Patterns are used in combination • e.g. Factory can be used to create different Command object instances based on criteria • e.g. this can be useful for Networking where the incoming data is in the form of raw bytes and you want to convert these to some form of Command object • If the byte stream starts with 0 create Command0 with the rest of the data as parameters • If the byte stream starts with 1 create Command1 with the rest of the data as parameters
Conclusion • Patterns give the developer many possible ways of solving a problem • gives you the benefit of tapping the experience of others • Patterns however are not a magic bullet • You can still shoot yourself in the foot if you choose the wrong pattern for your application • It is important to • weigh the pros and cons of different patterns • take into account what the future holds for your application • choose the pattern that can address both the above