1 / 13

ECE452/CS446/SE464

ECE452/CS446/SE464. Design Patterns: Part I Answers A Tutorial by Peter Kim Based on slides prepared by Krzysztof Pietroszek. Problem 1. public class Person { protected String name; … public String getName() { return name; } public void setName(String name)

emilie
Download Presentation

ECE452/CS446/SE464

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. ECE452/CS446/SE464 Design Patterns: Part I Answers A Tutorial by Peter Kim Based on slides prepared by Krzysztof Pietroszek

  2. Problem 1 public class Person { protected String name; … public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() {…} public void setAge(int age) {…} } public class GUI { … public void setPerson(Person person) { nameLabel.setText(person.getName()); ageLabel.setText(person.getAge()); } } To display Person on GUI, GUI.setPerson(Person) must be invoked explicitly. What design pattern could be used so that changes to Person are more implicitly and “automatically” reflected in GUI and potentially in other classes that are interested in Person? Show a) the design pattern and b) an interaction diagram demonstrating a change in Person

  3. Answer 1a): Observer (behavioural) design pattern • What’s the problem between Observer.update() and Subject.getState() here? • Granularity of updates (e.g. age updated even though only name was changed) Person GUI -name: String -age: int -nameLabel: Label -ageLabel: Label 1 * +setName(name: String): void +getName(): String +setAge(age: int): void +getAge(): int +GUI(person: Person): GUI +update(): void { this.person = person; this.person.attach(this); } { nameLabel = person.getName(); ageLabel = person.getAge().toString(); } { this.age = age; notify(); } { this.name = name; notify(); }

  4. Answer 1b) :Program p := new Person() p:Person gui := new GUI(p) gui:GUI attach(gui) setAge(23) notify(AGE) update(AGE) getAge() Overlapping execution occurrences on the same lifeline are represented by overlapping rectangles

  5. Problem 2 • Assume that you are implementing a file system. The main concepts in a file system are directories and files. A directory may contain several files and directories. Additionally, you would like to treat files and directories in a uniform way as nodes, i.e., you would like to be able to write code that can treat both files and directories using the same interface. • What design pattern could you use to achieve these goals? • Draw a class diagram explaining your design.

  6. Answer 2 • Composite Pattern

  7. Problem 3: Java API related What design pattern is java.util.Collections.sort(List, Comparator) method an example of? Draw a class diagram and draw some sample code. package java.util; public interface Comparator { public int compare (Object arg1, Object arg2); … }

  8. Answer 3: Strategy public class AgeComparator implementsComparator { … public int compare(Object arg1, arg2) { Age a1 = (Age)arg1; Age a2 = (Age)arg2; if(a1.getValue() > a1.getValue()) return 1; else if(a1.getValue() < a2.getValue()) return -1; return 0; } } Collections.sort(ages, new AgeComparator()); Inside java.util.Collections.sort(.), comparator.compare(Object, Object) is used *somehow*: void Collections.sort(List list, Comparator comparator) { … int comparison = comparator.compare(list.get(i), list.get(i+1)); … }

  9. Problem 4: Java API related Consider the following Java I/O streams, where an indentation represents class inheritance (e.g. FileOutputStream extends OutputStream). OutputStream: the generic output stream. FileOutputStream: output stream for writing to files. FilterOutputStream: takes a regular OutputStream as an input and performs some filtering operations on it. DeflaterOutputStream: performs compression on the input OutputStream. ZipOutputStream: produces a compressed output of “Zip” format. GZIPOutputStream: produces a compressed output of “GZIP” format. What design pattern is evident (hint: FilterOutputStream)? Draw a class diagram and provide a sample code.

  10. Answer 4: Decorator (Structural) public class FilterOutputStream extends OutputStream { /** * The underlying output stream to be filtered. */ protected OutputStream out; /** * Creates an output stream filter built on top of the specified * underlying output stream. */ public FilterOutputStream(OutputStream out) { this.out = out; } public void write(int b) throws IOException { out.write(b); } … } 1 1 public class DeflaterOutputStream extends FilterOutputStream { public void write(int b) throws IOException { bCompressed = compress(b); super.write(bCompressed); } }

  11. Problem 5 a) A commonly cited advantage of the Decorator design pattern is that it avoids subclass explosion. Explain this using an example. b) Commonly cited disadvantages of the Decorator design pattern are that it allows i) identity crisis and ii) interface occlusion. Why are these problems not evident with subclassing? Explain these using an example.

  12. Answer 5a) Component • N functionalities typically represented in N subclasses • But representing combinations of N functionalities as subclasses means, for example, {(N choose 1) + (N choose 2) + … + (N choose N) – invalid number of combinations} subclasses Frameable Scrollable Resizable Frameable Scrollable Frameable Resizable Scrollable Resizable FrameableScrollable Resizable • Using the Decorator design pattern • N combinations are represented through, for example, {(N choose 1) + (N choose 2) + … + (N choose N) – invalid number of combinations} objects. However, there are only N classes. Object explosion not as bad as [sub]class explosion as the former is more manageable and much smaller. Component 1 ComponentDecorator Window 1 Frameable Scrollable Resizable Objects are composed from right to left. E.g. fs means that s:Scrollable is composed by f:Frameable 3 choose 1 f: Frameable s: Scrollable r: Resizable 3 choose 2 fs: Frameable fr: Frameable sr: Scrollable 3 choose 3 fsr: Frameable

  13. Answer 5b) Basically, problems arise because there are two objects, whereas with subclassing, there is only one object. Component 1 paint(): void dispose(): void • Interface occlusion • Interface of the component is blocked by the decorator in the sense that the decorator has to explicitly delegate methods to the component • E.g. If interface of Component class evolves (e.g. dispose() is added), then the implementation of the decorator must also evolve so that the method calls will be delegated to the component (e.g. dispose() calls c.dispose()). c.paint(); ComponentDecorator 1 paint(): void Frameable Scrollable Resizable Client1 • Identity crisis • Clients are referencing the undecorated object ‘c’ initially. ‘c’ is decorated with ‘cd’, an instance of ComponentDecorator. Clients must update the reference ‘c’ to ‘cd’. Hard to update all the clients (especially with many scattered object references), e.g. Client1 is not updated. • With subclassing, there’s only one object so there’s no such problem c: Component Client2 cd: ComponentDecorator

More Related