Skip to main content

CSC 321.01, Class 20: Design patterns, continued

Overview

  • Preliminaries
    • Notes and news
    • Upcoming work
    • Extra credit
    • Questions
  • Exploring more patterns
    • A process
    • An example
    • The patterns

Preliminaries

News and notes

  • Please sit with your pattern group
    • Factory (any kind is fine): FA, SG, JM, JZ
    • Observer: MB, MG, AM, AM
    • Proxy: EB, BH, DN, MD
    • Strategy: GC, PK, JS, JRL
    • Template Method: WSC, NA, RS
  • Stickers.
  • There were a lot of problems with the pattern writeups. So I’m going to approach today’s class a bit differently than I’d planned. I’d also like you to rewrite your assignments to meet the (insufficiently well stated) goals.
  • Friday is our last CSC 321 class. So sad. But we’ll be together in CSC 322.

Upcoming work

  • Revised HW9: Document a Design Pattern due before spring break.
    • Make sure you have the problem, bad solutions, the pattern-based solution, and examples.

Good things to do (Academic/Artistic)

  • Faulconer gallery has two great exhibits.
  • Thursday Extra

Good things to do (Other)

  • Play on campus.
  • WGMC on Thursday at 6pm. Write a mission statement.
  • Little Mermaid Musical at HS.

Questions

How will you grade us?

Homework: Percent submitted on time * .90 + bonus for great answers

Journals: Percented submitted on time * .90 + bonus for great answers - loss for mediocre answers

Participation: .90 +/- noticably good or noticably mediocre

_Will we get feedback beyond the regular “Here are some really <word that Sam won’t say in class> answers and here are some really good ones?”

Only on the design patterns.

Will you let us argue our grades?

It seems like a bad idea, but probably.

Five patterns

How we’ll approach it

  • What is the underlying problem the pattern is intended to solve. (You may also want to give a realistic example.)
  • Pause: Everyone think about how you tend to approach those problems.
  • What does the pattern say a better way to solve that problem is?

My Adapter example

  • The problem: When I design a large software system, I specify the interfaces for all the components. While none of the components already exist, some things are similar.
    • E.g., “Workflow manager” needs a “quick FIFO to-do-list
    • QuickFIFOToDoList Needs methods addTask, nextTask, done?
    • Queue provides enqueue, dequeue, empty?
  • A typical solution:
    • We know how to implement queues, so just implement QuickFIFOToDoList using the strategy we’ve always used for implementing queues. (E.g., linked list with pointers to both ends.)
      • Reinventing the wheel is rarely a good idea, unless you really need different behavior.
    • Use the Queue that's already built in to Java: Everytime that QuickFIFOToDoList appears in WorkFlowmanager, replace it with `Queue`. (Similar search and replace on method names.)
      • Obscures our code.
      • Makes changes harder
  • The adapter solution: Write a really simple class that delegates most of the work to another class.

For our example

public class MyQuickFIFOToDoList implements QuickFIFOToDoList {
  Queue<Strings> core;

  public String nextTask() {
    return core.dequeue();
  }

  public void addTask(String task) {
    core.enqueue(task);
  }
}

This strategy lets us plan for the future. If we need to make any changes to semantics in QuickFIFOToDoList, they are localized to this one class. Plus our code is more readable.

The problems these patterns address

Factory How to create objects on the fly from one of many subclasses with the decision made at run time rather than compile time? Example: A video game needs to spawn monsters and the monsters change over time (different levels, etc.).

Observer We work in a world in which there is a subject and one or more observers. The observers need to know when the subject changes. MVC: If the model changes, the view should change. (E.g., Facebook)

Proxy You have an object that is expensive to create. You should only create the object when it’s really needed by the client. Or you want to enforce preconditions. The client still needs something to refer to, even thought it may not be completely needed.

Strategy Different algorithms can be appropriate for the same problem. For example, if we have a small list, we might use insertion sort and if we have a long list, we might use merge sort. The algorithm needs to be decided at run time, not compile time.

Template Method. You have multiple algorithms and you’d like to factor out the similarity in the algorithms. Or You have one algorithm, but you can make it behave differently using other functions as input. (E.g., sort in Scheme can behave differently depending on the comparator you give it.)

How we typically address these problems

Talk about the two that come immediately after your group (cycle around to the front). What would you do if you encountered that design issue when impelemnting a program?

We’ll look at how Sam remembers approaching each of these problems when he first encountered them.

Factory

A really big conditional

r = random(100);
if (level == 1)
  if (r < 20)
    return new WaterBottle();
  else if (r < 40)
    return new ExpoMarker();
  else
    return new Eraser();
else if level (== 2)
  if (r <30)
    return new LinuxWorkstation(50 + random(10));
  ...

Problem:

* Hard to read
* Hard to change at run time
* Not very modular

**Observer**

A busy loop

while (true) { if (subject.lastUpdated > lastUpdated) { lastUpdated = subject.lastUpdated(); showCurrentState(subject); } } ```

Proxy

Make the client pay attention to when it has an incomplete object (and it’s okay to do so) and when it needs the costly/heavyweight object.

Strategy

Curse Java for not being Scheme.

Template Method

Curse Java for not being Scheme.

How the patterns address the problem

Factory

Observer

Proxy

Strategy

Template Method