The Command Design Pattern (PDF)

Summary

This document explains the Command design pattern. It details the intent, implementation, and advantages of using the Command pattern in software development, along with examples and a discussion of different implementations and applications. The document also discusses the related concept of serialization, and its use in software applications.

Full Transcript

The Command Pattern The Command design pattern encapsulates commands (method calls) in objects allowing us to issue requests without knowing the requested operation or the requesting object. Command design pattern provides the options to queue commands, undo/redo actions and other mani...

The Command Pattern The Command design pattern encapsulates commands (method calls) in objects allowing us to issue requests without knowing the requested operation or the requesting object. Command design pattern provides the options to queue commands, undo/redo actions and other manipulations. Intent – Encapsulate a request in an object – Allows saving the requests in a queue ‫‪The Command Pattern -‬‬ ‫‪Implementation‬‬ ‫)‪ )stockMarket‬بنفذ العمليات الي بدي ياها كان في بيع وشرا ‪Receiver‬‬ ‫كل كالس من هدول الكالسات بتمثل استدعاء ميثود للريسيفر‬ ‫الي بالبوكس األصفر يعني ميثود استدعيتها من الريسيفر‬ ‫هو الي بنفذ وبستدعي بدون ما يعرف اشي ‪Invoker stockAgent‬‬ ‫‪Command interface‬‬ The Command Pattern - Implementation The classes participating in the pattern are: Command - declares an interface for executing an operation; ConcreteCommand - extends the Command interface, implementing the Execute method by invoking the corresponding operations on Receiver. It defines a link between the Receiver and the action. Client - creates a ConcreteCommand object and sets its receiver; Invoker - asks the command to carry out the request; Receiver - knows how to perform the operations; The Command Pattern - Here is a sample code of Example a classic implementation of this pattern for placing orders for buying and selling stocks: public interface Order { class StockTrade { public abstract void execute ( ); public void buy() { } System.out.println("You want to buy //ConcreteCommand Class. stocks"); class BuyStockOrder implements } Order { public void sell() { private StockTrade stock; System.out.println("You want to sel public BuyStockOrder stocks "); ( StockTrade st) { } stock = st; }// Client } public class Client { public void execute( ) { public static void main(String[] stock. buy( ); args) { } StockTrade stock = new } StockTrade(); //ConcreteCommand Class. BuyStockOrder bsc = new class SellStockOrder implements BuyStockOrder (stock); Order { SellStockOrder ssc = new private StockTrade stock; SellStockOrder (stock); public SellStockOrder Agent agent = new Agent(); ( StockTrade st) { stock = st; agent.placeOrder(bsc); // Buy } Shares public void execute( ) { agent.placeOrder(ssc); // Sell The Command Pattern - // Invoker. example class Agent { private m_ordersQueue = new ArrayList(); public Agent() { } void placeOrder(Order order) { ordersQueue.addLast(order); } public void processOrders(){ for(Order order: m_ordersQueue) order.execute(); } The Command Pattern The applicability of the Command design pattern can be found in these cases below: specifies or adds in a queue and executes requests at different moments in time offers support for undoable actions (the Execute method can memorize the state and allow going back to that state) structures the system in high level operations that based on primitive operations decouples the object that invokes the action from the object that performs the action. Due to this usage it is also known as Producer - Consumer design pattern The Command Pattern Undo and redo actions Some implementations of the Command pattern include parts for supporting undo and redo of actions. In order to do that a mechanism to obtain past states of the Receiver object is needed; in order to achieve this there are two options: Before running each command a snapshot of the receiver state is stored in memory. This does not require much programming effort but can not be always applied. For example doing this in an image processing application would require storing images in memory after each step, which is practically impossible. Instead of storing receiver objects states, the set of performed operations are stored in memory. In this case the command and receiver classes should implement the inverse algorithms to undo each action. This will require additional programming effort, but less memory will be required. Sometimes for undo/redo actions the command The Command Pattern The main advantage of the command design pattern is that it decouples the object that invokes the operation from the one that know how to perform it. And this advantage must be kept. There are implementations of this design pattern in which the invoker is aware of the concrete commands classes. This is wrong making the implementation more tightly coupled. The invoker should be aware only about the abstract command class The State Pattern The main idea of State pattern is to allow the object for changing its behavior without changing its class. Also, by implementing it, the code should remain cleaner without many if/else statements. In State pattern a class behavior changes based on its state. This type of design pattern comes under behavior pattern. In State pattern, we create objects which represent various states and a context object whose behavior varies as its state object changes. This pattern is close to the concept of finite-state machines. The State Pattern The state pattern is set to solve two main problems: Use the State pattern when you have an object that behaves differently depending on its current state, the number of states is enormous, and the state-specific code changes frequently. Use the pattern when you have a class polluted with massive conditionals that alter how the class behaves according to the current values of the class’s fields. Use State when you have a lot of duplicate code across similar states and transitions of a condition-based state machine. Example The State Pattern The State Pattern Advantages of State Design Pattern With State pattern, the benefits of implementing polymorphic behavior are evident, and it is also easier to add states to support additional behavior. In the State design pattern, an object’s behavior is the result of the function of its state, and the behavior gets changed at runtime depending on the state. This removes the dependency on the if/else or switch/case conditional logic. For example, in the TV remote scenario, we could have also implemented the behavior by simply writing one class and method that will ask for a parameter and perform an action (switch the TV on/off) with an if/else block. The State design pattern also improves Cohesion since state- specific behaviors are aggregated into the ConcreteState classes, which are placed in one location in the code. State vs. Strategy State can be considered as an extension of Strategy. Both patterns are based on composition: they change the behavior of the context by delegating some work to helper objects. Strategy makes these objects completely independent and unaware of each other. However, State doesn’t restrict dependencies between concrete states, letting them alter the state of the context at will. Iterator pattern iterator: an object that provides a standard way to examine all elements of any collection uniform interface for traversing many different data structures without exposing their implementations Element removal needs to know about internal structure of collection or different methods to access data from different collections 16 Iterator interfaces in Java public interface java.util.Iterator { public boolean hasNext(); public Object next(); public void remove(); } public interface java.util.Collection {... // List, Set extend Collection public Iterator iterator(); } 17 Iterators in Java all Java collections have a method iterator that returns an iterator for the elements of the collection can be used to look through the elements of any kind of collection (an alternative to for loop) List list = new ArrayList();... add some elements... for (Iterator itr = list.iterator(); itr.hasNext()) { BankAccount ba = (BankAccount)itr.next(); System.out.println(ba); } 18 Adding your own Iterators when implementing your own collections, it can be very convenient to use Iterators – discouraged (has nonstandard interface): public class PlayerList { public int getNumPlayers() {... } public boolean empty() {... } public Player getPlayer(int n) {... } } – preferred: public class PlayerList { public Iterator iterator() {... } public int size() {... } public boolean isEmpty() {... } } 19 The Visitor Pattern Motivation Visitor Pattern represents an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates. The Visitor Pattern Context: – Object interfaces are fixed and diverse, – Need to allow new operations, without coupling. Solution: – Represent operations to be performed as visitors, with the interface of every visitor representing the different kinds of objects. Consequences: – Can add new operations without changing objects, The Visitor Pattern The Visitor pattern is a way of separating the operation from the object structure and a way of collecting together the different implementations of an operation for different kinds of elements in the object structure. A Visitor class is created which knows how to perform a particular operation on the different kinds of elements in the object structure. Each type of element in the structure defines an accept() method that can accept any kind of Visitor. The Visitor is passed to each element in the structure in turn, by calling its accept() method and the Visitor then performs the operation on the visited element. One important consequence of this separation of object structure and operation is that we can later add a new operation (a new kind of Visitor) without having to modify the element classes of the object structure. Each type of Visitor defines several visit() methods, one for each kind of element. The Visitor Pattern The Visitor Pattern The participants classes in this pattern are: Visitor - This is an interface or an abstract class used to declare the visit operations for all the types of visitable classes. Usually the name of the operation is the same and the operations are differentiated by the method signature: The input object type decides which of the method is called. ConcreteVisitor - For each type of visitor all the visit methods, declared in abstract visitor, must be implemented. Each Visitor will be responsible for different operations. When a new visitor is defined it has to be passed to the object structure. Visitable - is an abstraction which declares the accept operation. This is the entry point which The Visitor Pattern ConcreteVisitable - Those classes implements the Visitable interface or class and defines the accept operation. The visitor object is passed to this object using the accept operation. ObjectStructure - This is a class containing all the objects that can be visited. It offers a mechanism to iterate through all the elements. This structure is not necessarily a collection. In can be a complex structure, such as a composite object. The Visitor Pattern The Visitor Pattern The Visitor Pattern The visitor pattern is a great way to provide a flexible design for adding new visitors to extend existing functionality without changing existing code The Visitor pattern comes with a drawback: If a new visitable object is added to the framework structure all the implemented visitors need to be modified. The separation of visitors and visitable is only in one sense: visitors depend of visitable objects while visitable are not dependent of visitors. Memento pattern problem: sometimes we want to hold onto a version of an important object's state at a particular moment memento: a saved "snapshot" of the state of an object or objects for possible later use; useful for: – writing an Undo / Redo operation – persistency; save / load state between executions of program We'll examine Memento in the context of saving an object to disk using streams 29 SHALLOW COPY VERSUS DEEP COPY When an object is cloned as a shallow copy: The original top-level object and all of its primitive members are duplicated. Any lower-level objects that the top-level object contains are not duplicated. Only references to these objects are copied. This results in both the original and the cloned object referring to the same copy of the lower-level object. When an object is cloned as a deep copy: The original top-level object and all of its primitive members are duplicated. Any lower-level objects that the top-level object contains are also duplicated. In this case, both the original and the cloned object refer to two different lower-level objects. Serialization serialization: reading / writing objects and their exact state using I/O streams – allows objects themselves to be written to files, across network, to internet, etc. – lets you save your objects to disk and 31 Classes used for serialization in java.io package: ObjectOutputStream class represents a connection to which an object can be written / sent (saved) public class ObjectOutputStream public ObjectOutputStream(OutputStream out) public void writeObject(Object o) throws IOException ObjectInputStream class represents a connection from which an object can be read / received (loaded) public class ObjectInputStream public ObjectInputStream(InputStream in) public Object readObject() throws Exception FileInputStream, FileOutputStream can be constructed from a file name String Serialization example recommendation: use a Memento class that has save/load code // write the object named someObject to file "file.dat" try { FileOutputStream os = new FileOutputStream("file.dat"); ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(someObject); os.close(); } catch (IOException e) {... } // load the object named someObject from file "file.dat" try { FileInputStream is = new FileInputStream("file.dat"); ObjectInputStream ois = new ObjectInputStream(is); ArrayList someList = (ArrayList)ois.readObject(); is.close(); } catch (Exception e) {... } 33 Making your classes serializable must implement the java.io.Serializable interface for your class to be compatible with object input/output streams public class BankAccount implements Serializable {... ensure that all instance variables inside your class are either serializable or declared transient – transient fields won't be saved when object is serialized 34 Memento pattern The memento pattern is a software design pattern that provides the ability to restore an object to its previous state (undo via rollback). The memento pattern is implemented with three objects: the originator, a caretaker and a memento. The originator is some object that has an internal state. The caretaker is going to do something to the originator, but wants to be able to undo the change. The caretaker first asks the originator for a memento object. Then it does whatever operation (or sequence of operations) it was going to do. To roll back to the state before the operations, it returns the memento object to the originator. The memento object itself is an opaque object (one which the caretaker cannot, or should not, change). Memento pattern

Use Quizgecko on...
Browser
Browser