oo-design-patterns.wiki (12191B)
1 == Object-oriented design patterns in UML == 2 design pattern: a reusable form of solution to a common design problem (like a 'template') 3 4 not a finished design, cannot be transformed directly into source code 5 6 not prescriptive, so don't memorize them. it's important to understand when and why they're needed. 7 8 speaking of, they're not always needed. don't over-complicate shit, you'll end up with a dumpster fire that nobody can maintain. 9 10 essential parts of a design pattern 11 * Pattern name 12 * provides common vocab for software designers 13 * Intent 14 * What does the design pattern do? 15 * What is its rationale and intent? 16 * What design issue/problem does it address? 17 * Solution 18 * the basic elements providing solution to the problem (structure, participants, collaborations) 19 * Consequences 20 * results and trade offs by applying the pattern 21 22 === Creational === 23 how objects can be created (maintainability, control, extensibility) 24 25 we study the singleton and factory method. then there are also abstract factory, object pool, and prototype. 26 27 ==== Singleton ==== 28 | Name | Singleton | 29 |--------------|---------------------------------------------------------------------------------------------------------------------------------| 30 | Intent | To ensure that only one instance of a class is allowed in a system. <br>Controlled access to a single object is needed | 31 | Solution | {{file:img/singleton-solution-diagram.png|Singleton solution diagram}} | 32 | Consequences | Controlled access to sole instance <br> Reduced name space (fewer 'global' variables) <br> permits variable number of instances | 33 34 Implementation 35 36 {{{java 37 public class SingleObject { 38 // private constructor, cannot be instantiated from outside 39 private SingleObject(){} 40 41 // create the one single instance 42 private static SingleObject instance = new SingleObject(); 43 44 // get the only instance 45 public static SingleObject getInstance() { 46 return instance; 47 } 48 49 public void showMessage() { 50 System.out.println("Hello world!"); 51 } 52 }}} 53 54 ==== Factory method ==== 55 | Name | Factory method | 56 |--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 57 | Intent | to abstract process of object creation so that type of created object can be determined at run time <br> to make design more customizable in terms of which objects can be created <br> avoiding the `new` operator because you don't want to hard code the class to be instantiated | 58 | Solution | {{file:img/factory-method-diagram.png|Factory method diagram}} | 59 | Consequences | end up with dedicated class to create instances of objects <br> can pass arguments to the class to control the features of the objects | 60 61 Implementation 62 63 {{{java 64 public class ShapeFactory { 65 public Shape getShape(String shapeTYpe) { 66 if (shapeType == null) { 67 return null; 68 } 69 if (shapeType.equalsIgnoreCase("CIRCLE")) { 70 return new Circle(); 71 } 72 else if (shapeType.equalsIgnoreCase("RECTANGLE")) { 73 return new Rectangle(); 74 } 75 else if (shapeType.equalsIgnoreCase("SQUARE")) { 76 return new Square(); 77 } 78 79 return null; 80 } 81 } 82 }}} 83 84 === Structural === 85 how to form larger structures (management of complexity, efficiency) 86 87 adapter is studied in this course. also have proxy, bridge, decorator, facade, flyweight, composite, private class data. 88 89 ==== Adapter ==== 90 | Name | Adapter | 91 |--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 92 | Intent | to convert interface of class into another interface <br> to let two or more classes with incompatible interfaces work together <br> to wrap an existing class with a new one <br> to have a kinda homogeneous interface that masks diversity of some set of various objects | 93 | Solution | {{file:img/adapter-diagram-1.png|Adapter diagram 1}} {{file:img/adapter-diagram-2.png|Adapter diagram 2}} | 94 | Consequences | single class is responsible to join functionalities of independent/incompatible classes | 95 96 Implementation 97 98 {{{java 99 public class Wrapper { 100 // the wrapped object 101 private LegacyComponent legacyComponent; 102 103 // constructor 104 public Wrapper (LegacyComponent instance) { 105 this.legacyComponent = instance; 106 } 107 108 // call to wrapped method 109 public int doThis() { 110 int result = 0; 111 float value = this.legacyComponent.doThat(); 112 // magic the value into an integer somehow, then 113 return result; 114 } 115 } 116 }}} 117 118 === Behavioral === 119 how responsibilities can be assigned to objects (objects decoupling, flexibility, better communication) 120 121 we study observer and chain of responsibility. there are also command, interpreter, iterator, mediator, memento, null object, state, strategy, template method, and visitor. 122 123 ==== Observer ==== 124 | Name | Observer | 125 |--------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 126 | Intent | to let some object(s) be notified of state changes in other objects in the system <br> when on object changes state, all dependents are notified and updated automatically | 127 | Solution | {{file:img/observer-diagram.png|Observer diagram}} | 128 | Consequences | supports broadcast communication <br> state changes in object(s) should trigger behavior in other objects <br> you can reuse objects without reusing their observers and v-v. <br> you can remove observers without changing the subjects | 129 130 Implementation 131 132 {{{java 133 public abstract class Observer { 134 protected Subject subject; 135 public abstract void update(); 136 } 137 138 class MappingRover extends Observer { 139 // specify observed subject in constructor 140 public MappingRover(Subject subject) P 141 this.subject = subject; 142 subject.attach(this); 143 } 144 145 // observers "pull" information 146 public void update() { 147 if (this.subject.getState() == 0) { 148 // map the environment 149 } 150 else { 151 // "come back home", whatever that means 152 } 153 } 154 } 155 public abstract class Subject { 156 private List<Observer> observers = new ArrayList<Observer>(); 157 private int state; 158 159 public int getState() { ... } 160 public void setState(int state) { ... } // and notify all observers 161 public void attach(Observer observer) { ... } // add to observers list 162 public void detach(Observer observer) { ... } //remove from observers list 163 164 public void notifyAllObservers() { ... } // run the update function for each observer in list 165 } 166 167 public static void main(String[] args) { 168 CentralStation cs = new CentralStation(); 169 cs.setState(0); 170 171 MappingRover rover1 = new MappingRover(cs); 172 CameraRover rover2 = new CameraRover(cs); 173 CameraRover rover3 = new CameraRover(cs); 174 175 cs.setState(1); 176 } 177 }}} 178 179 ==== Chain of responsibility ==== 180 | Name | Chain of responsibility | 181 |--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 182 | Intent | avoid coupling sender of request to receiver by giving more than one object a chance to handle request <br> chain receiving objects and pass request along chain until an object handles it (sequential) | 183 | Solution | {{file:img/chain-of-responsibility-diagram.png|Chain of responsibility diagram}} | 184 | Consequences | Reduced coupling between objects (every object needs to know its successor) <br> handler(s) are not known a priori and a request might be unhandled <br> you can change responsibilities by changing chain at runtime | 185 186 Implementation 187 188 {{{java 189 public class Task { 190 private Coordinate coords; 191 private RequestEnum request; 192 193 // basic getters and setters 194 public Coordinate getcoords() { ... } 195 public setCoords(Coordinate coords) { ... } 196 197 public RequestEnum getRequest() { ... } 198 public setRequest(RequestEnum request) { ... } 199 } 200 201 public enum RequestEnum { 202 PICTURE, MAP; 203 } 204 205 public class Coordinate { 206 private float lat, lon; 207 208 // basic getters and setters 209 public float getLat() { ... }; 210 public setLat(float lat) { ... }; 211 public float getLon() { ... }; 212 public setLon(float lon) { ... }; 213 } 214 215 public abstract class TaskHandler { 216 TaskHandler successor; 217 publicc void setSuccessor(TaskHandler successor) { 218 this.successor = successor; 219 } 220 public abstract void handleRequest(Task task); 221 } 222 223 public class CameraRover extends TaskHandler { 224 public void handleRequest(Task task) { 225 if (task.request == RequestEnum.PICTURE) { 226 // take a picture 227 } 228 else { 229 // pass on to successor 230 if (successor != null) { 231 successor.handleRequest(request); 232 } 233 } 234 } 235 } 236 237 public class Main { 238 public static TaskHandler setUpChain() { 239 MapRover mapper = new MapRover(); 240 CameraRover photographer1 = new CameraRover(); 241 CameraRover photographer2 = new CameraRover(); 242 CameraRover photographer3 = new CameraRover(); 243 244 return mapper; 245 } 246 public static void main(Striing[] args) { 247 TaskHandler chain = setUpChain; 248 249 chain.handleRequest(...); 250 } 251 } 252 }}} 253