Don't read Design Patterns

home

 

Once you learn basic coding and start to write larger programs, it seems there must be some advanced concepts. If you use the internet, "Design Patterns" is the most popular one. People who like them really like them, but the explanations and examples seem very intimidating.

This is an explanation of how they fit into computer science, what you should be learning instead, and an explanation of what each Design Pattern is trying to say.

Very short version

Design Patterns are tricks to organize a very large program in a pure Object Oriented style. If you're having problems doing something, they won't help. If you're not trying to use a pure OOP style, they'll be awkward (if you have to ask whether you're trying to use a pure Object Oriented style, you're not.)

As far as getting better at programming, here's a short list of useful things to learn before Design Patterns. A 2nd semester programming textbook should have them: using loops to do common things with arrays. Lists - nicer versions of arrays. Using linked-lists to insert anywhere, or hash-maps for Cost["hammer"]=5.97;. Using 2D square and "ragged" arrays. Becoming more comfortable writing small classes with useful constructors, helper member functions, and passing/returning them in functions. Storing data in arrays of classes containing arrays of classes. Using pointer-style variables. Pointers to functions used as "plug-ins". Recursion. Becoming more comfortable with inheritance, virtual functions and the Animal a=new Cat(); trick. Using Big-O to analyze speed.

Design Patterns are meant for programmers who know most of that stuff. If a problem can be solved just fine with array tricks, Design Patterns won't mention it. They especially assume you're happy writing base classes with virtual functions, since many of them build from there.

Short Version

From about 1995 to 2000 the internet went public and grew into the first dot-com boom. There was a huge demand for web Java programmers: Object Oriented Programming was the new promising style, and Java was the hot new OOP language.

Meanwhile, in 1994, a book was written named "Design Patterns: elements of reusable object oriented software." It was two dozen programming tricks renamed and rewritten in Object Oriented style. Nothing special, but nothing wrong with it either.

The flood of new internet Java coders were mostly self-taught and didn't feel connected to traditional computer science. They were looking for guidance and that book was exactly what they wanted. Pretty soon employees were using the official Design Pattern names in meetings. More importantly, overwhelmed managers realized they could ask Design Pattern questions during performance reviews and for job interviews. At that point, whether they worked or not, Design Patterns were a part of the corporate Java world (and now its copy, C#).

Design Patterns today are those same two dozen tricks from that book, with very minor changes.

Software engineering

Software engineering is everything to do with managing and organizing programming projects. The Design Pattern book was originally a paper at a Software Engineering conference, because the authors were software engineering professors. A scattering of things in that field:

There's a well-known software engineering essay by Fred Brooks, an old-time IBMer, "The Mythical Man-Month". It's about how we have lots of software engineering guidelines, but writing a big program is still so chaotic. The name is about how we used to estimate time to write programs in man-months, which was a terrible idea (there's an old joke: at IBM they hire 9 women to make a baby in 1 month).

Internet essays on "Why use Design Patterns" also focus on that problem. We don't have a reliable set of rules to create big programs. It would be great if we did, really great. So try Design Patterns because, come-on, something has to work.

Brook's follow-up 10 years later was "No Silver Bullet". It's about how we're sure the next new thing will be the silver bullet that makes programming predictable. But in his opinion there probably won't be one. Maybe making big programs will always be a mess.

 

Object Oriented Programming

Design Patterns aren't about general programming. They're specifically about using a strict Object Oriented Programming style (it's in the name of the book). OOP means different things, but at the time it meant using classes and polymorphism for everything you possibly could. Here's the idea, going back a-ways:

The very first programs had only a "jump to any line" command. Clever programmers could use it to do anything they needed. Eventually two common jumping patterns emerged: a "do this or that" and a "repeat these lines while a condition is true". As you might guess, that's how we invented if/else's and while loops.

We eventually had a radical idea. What if we quit using jumps, and only used if's and loops? Your program would be a little bigger and slower, but sooo much easier to read and debug. Older coders mocked the idea, but it worked. Before Structured Programming we thought the secret was adding features. We learned that cutting features and forcing a single style could give us more reliable code, written faster.

In the 1990's we thought we had something similar. We had classes and polymorphism, but we used them as needed, mixing in all sorts of other tricks. OOP's idea was that limiting ourselves to only communicating classes might be another big gain through simplification. Hopefully programming would be merely arranging classes, using a UML diagram, full of helpful tools and warnings. It didn't work out. OOP programs take about as long, with about as many bugs, as anything else. But it was worth trying and we learned some things.

The Design Pattern book was written at the start of that, in response. It was a simple survey of OOP tricks people around the world were using, and what names they were calling them. Very unpresumptuous.

Things to note about Design Patterns

A summary and some new things:

 

Explanation of each Design Pattern

Officially, the things in that one book are the real design patterns. But there are a few things the book describes and says aren't design patterns, but now people say they are. I listed those, too.

When the book was written, Java and C# didn't exist. The examples tend to be in C++ or SmallTalk (an experimental OOP-like language like nothing you've seen). They can be very difficult to read now, so I'm mostly skipping them.

Some of the descriptions in the book often use old, experimental terms, or just odd phrasing that sounded fine to a 1990's software engineer, but is awkward now. Translating each term wouldn't be helpful. I tried to just restate them in plain English.

Facade, Adaptor

This is when we have a class we like mostly the way it is, but we need to tweak the functions a little. To do that, make a new class holding the original, but with the functions the way you want them.

Our new class can't inherit from the original since the functions we don't like would still be there. Instead, the new class has the original as it's only variable. In this example, DogWrap wraps Dog. It changes getKilos to getPounds, but leaves getName the same:

class DogWrap { // wrapper on Dog
  Dog d; // does all the work

  string getName() { return d.getName(); } // a "pass-through"

  // change getKilos to getPounds:
  float getPounds() { return d.getKilos()*poundPerKilo; }
}

Notice how functions we don't want to change still need to be written again, like getName.

The books says a Facade is when you want to change the functions, and an Adaptor as when you need to. That's an odd distinction. Most people call it a wrapper - the new class wraps around the old one.

Proxy

This is a normal computer term which wasn't changed when they put it in the book. It means to add an interface or wrapper that does some buffering. It's purpose is speedier execution.

For example, a typical file-reading class lets you read 1 line at a time from the disk. But for speed, it actually grabs a full disk page into a buffer, reads lines from there, and gets the next page from disk when that runs out. Graphics cards use the trick in reverse for commands. Instead of running them as they're sent, it saves them. When you finish, it reorganizes the list, for speed, and then runs them for real.

This is odd one since it's not about organizing or object oriented code. It's only a speed trick.

Command-I

Command is another word for a plug-in or a callback: a button in a menu has a spot to plug-in what it does. We often do this with a function. Here's a button class that takes one. You can give it any function with no inputs:

class Button {
  ...
  
  public System.Action clickAction = null; // <-plug-in function slot (C#-style)
  
  void handleClick() {
    ...
    // run the plug-in function if we have one:
    if(clickAction!=null) clickAction(); 
  }

Outside the button, we make any function and plug it in:

void makeBunnyJump() { ... }

  button1.clickAction = makeBunnyJump;

This is a big deal: a generic Button class can call any of our functions through the magic of function pointers. Function pointers are useful for lots of things, which is why we study them.

The official Command pattern uses classes. It's the same idea - Button has a dangling pointer which can aim at any function we write. But it has more code which, if you like Object Oriented-ness, helps explain it all better.

The old function pointer turns into a specially made base-class pointer:

class ButtonActions {
  public virtual void clickAction() {}
  public virtual void doubleClickAction() {} // we can group several callback functions
}

  // inside the Button class:
  public ButtonActions myActions; // <- slot for plug-in class
  
  void handleClick() { if(myActions!=null) myActions.clickAction(); }
  ...

ButtonActions does what all base classes do - it establishes the functions we'll be using. Inside Button, we can even mouse-over it and read the definition.

Users add the real actions by making a sub-class of ButtonActions, overriding the functions. This makes the bunny jump on a click, and does nothing on double-clicks:

class BunnyButtonJump : ButtonActions {
  public override void clickAction() {
   // code to make the bunny jump
  }
}

  // hook our bunny jump to button1:
  button1.myAction = new BunnyButtonJump();

If you like OOP, inheriting from BunnyActions is a helpful comment. It lets you know BunnyButtonJump is for a Button plug-in.

You may notice some class abuse going on here. The class doesn't have any variables. It's really 2 ordinary functions. But we needed myActions.clickAction() to be virtual, which meant we needed to use new to make an empty object. Yeesh. One of the tricks of OOP is that not all classes stand for actual things - some are only virtual function tricks like this.

Inversion of Control

This one is so obsolete that it's fun to read about. It means having buttons that can tell the program when they've been clicked. Huh? That's the normal way buttons have always worked. Inversion of Control is from before we even had pretend screen buttons and mice. Here's the way it's described:

25 years ago programs printed "Enter name:" and waited, like in the movie War Games. All data needed to be hand typed when the program told you to, in the order it told you to. The program controlled (there's that word) when inputs happened. The was the way programs had always worked. Mostly. Some early military programs used light-pens. But everyone else just typed when it told you to.

Mice and windows with text-boxes and buttons was a big change. Our new programs could just wait for the user to click or type anywhere. That required a whole new way of programming the inputs. It was like they were running us - control was inverted from the normal way.

What specific things are inversion of control? Definitely OnButton1Click. Those are the functions that just sit there, automatically running when button1 is clicked. Probably also the polling method where we check "was the mouse clicked" 10 times a second. IoC was a general term. Saying "Use IoC" is the same as saying "read from your buttons with a way to read from buttons".

The term has also been recycled into "IoC framework", to mean any program that helps you make buttons. For example, Visual Studio in Forms mode, where you just drag them onto the screen and double-click to create OnButton1Click. So basically, it's a fancy way of saying "visual editor".

Singleton

This trick has to do with global variables. Using them makes the program harder to test, but sometimes there's no other good way. Singleton doesn't get rid of globals, but it simplifies them. We'll put our globals in an instance of a class with a true global pointing to it. There's no one thing that fixes, but it does a few small things.

For an example, we were using left and right as globals. Now we move them into the class Borders and have real global BDR points to the single copy:

class Borders { // these will be the program's globals:
  public int left, right;
}

public Borders BDR; // global variable aimed at the only Borders object

  // in main program create 1 instance and set the global:
  BDR = new Borders();  

It looks like we converted all of our globals into just one - BDR. But not really. Our program looks the same, with the same use of globals:

// old code:
x += left; if(x>right) ...

// new code. No real change:
x += BDR.left; if(x>BRD.right) ...

They can help initialize globals. Often we need to build a global list or something, before the program runs. In a large program, it's easy to do that twice, or not at all (everyone thinks it was someone else's job). Singletons don't really fix that, since they also need to be created somewhere, but they make it more obvious, and we can put set-up code right in the constructor.

It's called singleton since it's a class which is supposed to have only a single copy. But a nice use is having several. We can move BDR - the pointer - between different copies, for testing, say.

It's also common to realize that globals aren't globals. You have a game using globals for "the" score. But then realize each level has a separate score. If you already had the score variables in a class, it's a little easier to do that.

Just so you see it, the standard Singleton set-up puts the global pointer inside the class, alongside a function to create the single copy:

class Borders {
  public int left, right;
  
  public static BDR; // the global pointer to the 1 instance of Borders
  
  // someone needs to call this once:
  public static makeBorders() {
    if(BDR!=null) print("Yikes! There is already a copy"); quit;
    BDR = new Borders();
    // extra initializing here:
  } 
}

Now our main program needs just Borders.makeBorders(). The real global variable is Borders.DBR, and finding left is Borders.BDR.left.

Composite

This is another name for a tree. Why does a standard computer science thing like a tree need a special OOP name? Well, I think it's because we use trees in two general ways:

Some things are logically trees. Folders, or robots made from snapping a block onto one other block. It even turns out math expressions are best described as trees. This represents 4*(5+3). You should be able to see how 5+3 has to be added first:

   *
 /   \
4     +
     / \
    5   3

It seems fine to design classes to use trees for things that are best described as trees.

The other trees are about optimized data storage. It's when our items are in a list, but for speed we use a B-tree, red/black-tree or one of the many others that runs faster depending on the exact way we're using it. Computer scientists study these lots, but they're used behind-the-scenes. We shouldn't be thinking of them when we design the program. That's my theory why the word Composite means tree.

If you aren't already good with trees, seeing them in the Composite design pattern is a backwards way of learning them. To use trees you need to know recursion, since trees are a recursive data-structure (which is another thing to learn). But to know recursion you have to practice with basic non-tree recursion. That's why I say to learn 2nd semester programming - recursion is right there as a topic.

Command-II

Command also has a second completely different meaning. Why make up a different word? I assume it's because the book was about what people were actually doing, and they were calling both of these Commands.

This command means to create an item which holds a command. It replaces a direct function call with a 2-step process. Instead of calling button1.hide() we could create the command [obj: button1, action:hide] and send it to the menu. Hopefully it figures it out and does it.

One advantage is looser coupling. We don't need to find button1 or know it has a hide member function. We might even send commands to a middleman and not need to know about the menu class. We need to know about the new command class, but it's probably more generic.

The other advantage is being able to save a list of commands. We could log them for security, use them for undos or playback, or as a "here's what you missed" if someone joins late.

Dependency Injection

This says that if a class needs to use anything outside of itself, it should have a generic pointer to it. Not a global - there should be a pointer inside the class. The main program will need to set it during initialization - that's what "injection" is supposed to mean.

Suppose we have several Orc monsters which try to run at the player. DI says they won't find the player using a global. Instead, each orc will have it's own personal player-link. Part of DI is getting rid of globals, and this is the only way to do it. DI also says that if you own optional parts, you don't even create them. If each orc can have a pet worg, in several varieties, the system will create your pet doggie and hook you to it.

The way it actually works involves two basic computer things: the interface base class and virtual function trick, and dependancies:

Suppose orcs can have a pet red, blue or grey worg. Each acts differently so has it's own class. This code seems like an obvious way to do it:

class Orc {
  ...
  // Our pet. Only one of these will be non-null:
  redWorg rw;
  blueWorg bw;
  greyWorg gw;
  
  public void setPet(int worgType) {
    rw=bw=gw=null; // blank out any old pets
    if(worgType==0) rw=new redWorg();
      ...

The code will have lots of IF's for the worg types, which is a pain. If we create more types of worgs we'll have to add even more. A different problem, we always need all 3 worg types. Even if we never use redWorgs in this project, we still need them present for Orc to compile. That's the definition of a dependency - things you can't compile without.

A base class solves the IF problem and the dependency problem. We'll make an abstract class WorgBase and have all Worgs be sub-classes:

abstract class WorgBase {
  public virtual void rest();
  public virtual void attack();
  ...
}  

class Orc {
  ...
  WorgBase myPet; // can aim at any type of worg

Orc no longer depends on any actual worg types, but can point to any of them. Of course, the setPet function needed to be cut. We can no longer create our own worgs. The master program will need to create the particular red, blue or grey and aim our myPet variable at it.

This is 100% standard use of base classes. Command-I with the ButtonActions base class is wonky, but WorgBase is perfect. Using a base class as a pointer alllows you to point to any subclass, without needing to depend on it. If someone invents a new Worg, the master program needs to know about it, but it will plug into us just the way we are.

In Dependency Injection, classes use base-class pointers to find anything outside of themselves. That eliminates most dependencies, but makes it so we can't create things only we use - the worgs. Suppose a Menu class uses the input system, and needs to know about borders, and might have a personal button animation class. It will have 3 pointers of types: genericInput, Borders, and genericButtonAnimate (there are several ways to animate buttons, which are subclasses). The system creates your button animator, then links all three.

Writing a master program to create and link everything is a huge pain. In practice, most spiffy editors do it for you. The menu class has a drop-down with every button animation option. The system will automatically write code to create and link the one you select. These are sometimes called DI frameworks. Pretty much any system that invisibly creates or sets things is technically a DI framework. You probably have one in your home.

The last thing to know is DI uses the word dependency wrong. You can't inject a dependency. That doesn't even make any sense - dependencies are in the written-out class, not in how you use it. It should really be called "dependency removal, external link assigment".

Interpreter

This is making a mini-language, then writing code to read it. As a crude example, a shopkeeper in your game might say: "$charName$, welcome to $cityName$". Your program would know to substitute the right words. Or, a similar idea, the AI for a guard might be written "W[3,4]P(8)W[0]", which means it walks to station 3 or 4, pauses for 8 seconds, then walks back to station 0. You'd write code that knows how to read that, then you have an easy way to make paths.

It's an old trick, perfectly fine. It's not especially OOP, but not not OOP either. And Interpreter is a real computer word for a program which reads and directly runs some code, so it's being used correctly here.

Decorator

This one is about changing how a preset class works, on-the-fly, in a fully Object Oriented way. If you're not trying to be fully OO, there are easier ways. But it's such a cool trick and shows some neat ideas.

We can change how functions work by using a wrapper. But that's a permanent change at the start of the program. What if we want to change some functions midway through running, then again later, while still running? We could build those changes into the class as options, but often we have a pre-written, tested class. That's a big part of designing large programs - finding a way to use pre-made things as-is, instead of requesting a bunch of new changes.

Our plan is to use the wrapper method, but reworked in a way where the class starts normal, but we add a new wrapper for each change. If we changed 2 functions, then changed the 1st one back, the class will have 3 wrappers around it. It's crazy, but it just might work.

The first thing is to fix a problem with wrappers. Before, DogWrap was a different class from Dog. But now, we need everything to all be the same class. After wrapping a Dog, we need to still have a Dog, so we can keep adding wrappers to Dogs. We'll solve it with a fake base class (which seems complicated, but is sooo object oriented):

abstract class Dog { // <- everything inherits from this
  virtual string bark();
  virtual void eat(Food f);
}

class BasicDog : Dog { // <- this is the standard dog
  // the real dog variables and functions
}

// normal dog:
Dog d1 = new BasicDog();

We now have a regular Dog variable, which could be pointing to any sort of Dog, but currently points to a basic one. Each possible change requires a new wrapper class, also inheriting from Dog. This one changes the eat() function to go slower:

class EatSlowDog : Dog { // <- inherits from  Dog
 // holds the original Dog ... or a wrapped Dog:
  Dog d;
   
  string bark() { d.bark(); } // pass-though

  void eat(Food f) { new slow-eat code here }
  
  // constructor:
  EatSlowDog(Dog oldDog) { d=oldDog; }
}

To change d1 into a slow-eating dog, we add that wrapper around it: d1=new EatSlowDog(d1);. The old d1 is now inside the new one. Pretend we have another wrapper to make it bark softly. d1=new BarkSoftDog(d1); adds soft-barking to the already slow-eating d1. We have a wrapped wrapper, with the original basic dog deep inside.

The whole thing is overly-complicated and unnecessary, but it's so cool that it even works.

Today, we'd do the same thing with a base class as a member. Here b will point to any bark subclass, which could be changed any time while running:

class Dog {
  BaseBase b; // base class pointing to any real bark class
  EatBase e; // ditto
  
  void bark() { b.bark(); } // works because bark() is virtual
  void eat() { e.eat(); }
}

d1.b=new BarksLow(); would change us to a low-barking dog.

Decorate is also a normal computer science term. It's a reference to decorating a holiday tree - it means adding some temporary information to a class. Suppose Dogs have an extra general purpose int, and you temporarily use it to rate them for adoption by one family. We'd say we're decorating the Dogs with that rating.

Visitor

This is another Object-Oriented puzzle. It solves a real problem, but the Visitor trick is an overly complicated way to do it.

The problem is this: suppose we want to loop through an array of Animal's, filled with Cats and Dogs, running a function that works differently for each. We'd normally write a virtual function. It's exactly what they're for. But the same as with Decorator, the class is written, tested, and we don't want changes this late.

At first it might seem like overloaded functions would work. They don't since they don't know about subclasses. Here's what an attempt would look like:

// overloaded petRating function, for each subclass:
int petRating(Dog d) { return .. } // math for Dog
int petRating(Cat c) { return .. } // math for Cat

for(int i=0; i<A.Length; i++)
  petRating(A[i]); // <- an error. Looking for the Animal version

petRating(A[i]) is using an Animal variable, so tries to call petRating(Animal a). Only a virtual member function would know to check the subclass of what it points to. If you use C# and know about extension methods, they won't work for the same reason. They're merely a trick so you can write normal functions as if they we member functions. But they're not and can't be virtual.

One obvious solution is manually checking the subtype. It's the exact thing virtual functions do, except written out by hand. Here petRating does it for any Animal input:

int petRating(Animal a) {
  // run a different equation for Cats and Dogs:
  Cat c = a as Cat;
  if(c!=null) return .. ; // insert math for cats
  Dog d = a as Dog;
  if(d!=null) return .. ; // insert math for dogs
  return -99; // ? neither animal
}

It works, but we invented virtual functions as a replacement for this. They invisibly run those IF's, but faster and automatically grow when we write new subclasses.

The Visitor pattern is a way to trick a class into making anything run as if it were virtual. It's sooo complicated. First we have to "enable" it in the class. Part I of that is a base class:

// base class with generic slots for 1 cat function, and 1 dog function:
class AnimalVisitor {
  virtual int catIntVisit(Cat cc);
  virtual int dogIntVisit(Dog dd);
}

This is specially written to go with Animal. We'll see it used later. Obviously all it does is package the functions for each subclass. It's the same sort of class-abuse we saw in Command-I.

To use it, write your real functions in a subclass:

// real functions, written as a subclass:
class petRating : AnimalVisitor {
  override int catIntVisit(Cat c) { ... } // cat math
  override int dogIntVisit(Dog d) { ... } // dog math
}

// this is what we send:
AnimalVisitor petRater = new petRating();

The petRater variable is an AnimalVisitor, which Animals will know how to use, but it's really a petRating object, which is the math we wrote just now. The same sort of nonsense as the Command-I pattern.

Now back to how the original Animal class knows how to handle visitors. Virtual receiveVisit is written to take our special helper AnimalVisitor:

class Animal { // base class simply establishes the function:
  ..
  virtual int receiveVisit(AnimalVisitor av);
}

Each subclass overrides this to manually pick out their function. Cats run the cat one, Dogs the dog one:

class Cat : Animal {
  ..
  int receiveVisit(AnimalVisitor av) { return av.catIntVisit(this); }
  //                                     cat cat cat!!
}

class Dog : Animal {
  ..
  int receiveVisit(AnimalVisitor av) { return av.dogIntVisit(this); }
  //                                   dog  dog  dog!!!
}

Notice how they flip it around. A Cat gets an AnimalVisitor input, which it runs with itself as the input. It's the trick to enable virtual function use.

We can finally run it. Look how pretty this is:

AnimalVisitor petRater = new petRating(); // repeat from before

for(int i=0; i<A.Length;i++)
  total += A[i].receiveVisit(petRater);

Let's assume A[0] is a Cat and walk through the steps: A[0].receiveVisit(petRater) is virtual. It calls the Cat version, which executes petRater.catIntVisit(A[0]). That runs the Cat override from our perRating class, getting the correct rating for this Cat. Whew!

It seems like a crazy amount of work just to avoid a few IF's, but you have to admire that it even works at all.

Visitor is special since it's either enabled on the code you want to use, or not. You don't have to think whether to use it - if a class has a receiveVisit function, it wants you to run the Visitor pattern on it. Otherwise you can't.

BONUS: for real Visitor looks even worse than here: the real visitor pattern uses overloading in the visitor class!! I named my two functions catIntVisit and dogIntVisit. For real they name both intVisit. Since the inputs are Cats vs. Dogs, the computer can easily tell them apart. It's simple overloading, so it's exactly the same as using different names, but harder to read.

Observer

This isn't an actual trick, and it's about speed, not organization. The situation is you have one class displaying some data, maybe a pie chart. Another class holds the data, and sends a redraw command after each change. If there are a dozen changes all at once, redraw is uselessly called a dozen times in a row. We should figure out a way to delay redrawing until all changes are made.

The Observer Pattern is just some suggestions. Maybe speed isn't a problem, so don't worry about the extra redraws. Or get rid of automatic redraws. Instead, anyone making changes needs to manually call redraw. Or we do something fancy with a needsRedraw flag.

The normal word for a "notify me of changes" class is a Listener. Generally a Listener needs to know about and react to every single thing that happens. If we add 1 three times in a row, a Listener wants to be called 3 times. An Observer is a type of Listener where that isn't true, which might mean we can skip some, or not.

Service Locator

This is Singleton for things like files and databases. Those things are basically globals - there's one copy everyone shares - but since they're so complicated we might call them Services. Like Singleton, we'll create an object holding them with a global pointer to it. So still globals.

Then we do one more standard thing. Instead of just putting the pointers there, like DT.theDatabase, we use a function: DT.getDatabase(). Throwing a function in the middle of anything gives us a chance to play around. If we have some sort of back-up filesystem that rotates, the function call can handle it invisibly.

State

This is another Object Oriented way of doing something we can already do just fine the normal way. It's about using State Machines.

If you haven't seen the State Machine trick, it's using a variable to remember what you were doing (what state you're in). We can use an int variable, but it's nice to use an enumerated type:

enum JumpStates {waiting, launching, soaring, landing};
JumpStates js=waiting;

Our code uses js to decide what to do, changing it as needed:

if(js==waiting) { if(spaceKey) js=launching; force=0; }
else if(js==launching) { 
  if(abortKey) js=waiting;
  else { force+=t*0.4; if(force>5) js=soaring; } // lift-off speed is 5
}
else if(js==soaring) { // and so on
...

You'll also see pre-made systems to make that easier, or GUI's where the states are circles with arrows showing when to change from one to the other. Those are just normal, and aren't the State Design Pattern.

The State Design Pattern uses classes and a virtual function to make it more OOP. We make an abstract State class with a sub-class for each real state:

// abstract class with 1 function:
class JumpState { virtual doAction(); }

// subclasses for each state 
class Waiting : JumpState { 
  void doAction() { if(spaceKey) ... }; // same code as before
}

class Launching : JumpState { 
  void doAction() { // same code as before
   force+=t*0.4;
   if(force>5) backpointer.js=new Soaring();
  }
}

The reason for this is so our main loop can be just js.doAction();. Since js is an abstract super-class, that line looks up the real subclass, and runs the correct code. We eliminated the if's.

We change our state by creating a new instance of that state and assigning it to js. In other words, js starts as really being the Waiting subclass. When they press space, we toss that away and replace it with the Launching subclass. It's another example of total class abuse.

Iterator

This one is a specific low-level trick and is obsolete, sort of, since Iterators are now built into many languages. They're a way to write a loop which works on any type of list - one function can take an array, or a fancy array, or a linked list. For example:

int countSome(iterable L) {
  iterator iter=L.getIterator();
  while(!iter.done()) { // use the iterator to walk through
    if(iter.value() ..
    ..
    iter.next();
  }
}

Hopefully you can see how we're walking through the list using next(), value() and done(). Depending on the exact type of list, those could be adding to i, or following pointers, or anything. It works because Iterable is a base class. Any list that wants to work this way inherits from it and writes the exact next(), value() and done() it needs.

A problem with this is that we rarely want a loop that works with any kind of list. We usually choose the type of list depending on the exact thing we're doing, for speed. A loop that works in a certain way is probably best with one specific type of list.

The most common time you see this is with built-in list types, using built-in functions. If you have an array, but Sort takes an Iterable input, that probably means you can use it.

MVC

This is the idea that any program that displays things can break itself into a data-only part, and a display-only part. It stands for Model, View, Controller (model is the computer word for data). Controller means that instead of having the data and viewer talk to each other, we'll have them managed by a master program.

This is a very old one. Way back, programs purposely split into computing all results, and only then printing them. The view part was printing results on paper. When we first started writing graphical systems it was easy to forget that. But now it's just the basic idea of breaking a program into parts. Of course the display class is different than the data-managing class.

You'll often see MVC added to names of program-making GUIs. Microsoft's MVC web-page designer has you describe the inputs in one place, how they should look in another and builds the real HTML from those. Web style-sheets are about the same idea, except no one calls those MVC.

Factory/Abstract Factory

These are another version of the dependency reduction trick in DI, except for object creation. Say we need a link to another class to make Tabby cats. As usual, we'll use a base class, CatMaker, so we don't depend on Tabbys. Someone else will create our Tabby maker and plug it in:

// main program. Makes a CatZoo which makes Tabbys:
CatZoo cz1 = new CatZoo();
cz1.catFactory=new TabbyMaker();

 class CatZoo {
   CatMaker catFactory; // aimed at a TabbyMaker in this example
   
   Cat c1 = catFactory.makeCat();  // virtual function, creates a Tabby
   Leash l1 = catFactory.makeLeash();  // virtual function, leash for a Tabby

Factories often need to create several related items which need to be in synch. In this case all cats also have custom leashes. Each type of thing could have its own function (this example). Or we could have a single function where the input is what to make. That's the difference between a Factory and an Abstract Factory. It's not really a difference, and most people just say Factory for any class who's job is to organize creating families of new objects.

Prototype

This is for when your program needs to create complicated items, but in only a few settings. For example, 8 types of Tetris-like puzzle pieces. It says to get a master list with every item, then make the ones you need by copying.

By itself, that's pointless. Prototype is for when the original is somehow free. Maybe another program gave you the master list. Or, more commonly, you have a custom editor. You drag&dropped to make those 8 pieces. When you run, the system gives you a list with them pre-made.

Deep-down, prototype means "copying variables", which is so basic it hardly needs a name. But what can happen is you get so involved in trying to duplicate the steps to make something that you forget "I can just make a copy".

Builder

This is the idea of creating a complex object in 2 stages, using some sort of description format. Suppose our program now needs to make any sort of puzzle piece, on the fly. We'll make a grid that it fills in to describe the piece it wants. Your code can fill the spots in any order, taking its time. When you're done, the creation function can analyze the grid to create the real piece. It's a 2-step process.

Sometimes we do it all in one function, and it just happens to be easier to use two steps. But more often we use it like filling in an order form. Anyone can create an object by doing step 1, then sending it to the function running step 2 which gives us the completed item.

It's an old trick, but a good one, and not especially object oriented.

Flyweight

This says to factor your data like in a relational database. It's the standard way to avoid making lots of extra copies. Really, this trick is so obvious that it's hardly worth mentioning.

Suppose you have a list of people and countries. Obviously each person would have their country code. That's how a relational database works, and is also flyweight.

The obvious question is why that wouldn't always be completely obvious. Well, at first people might only need to know their national bird. Without thinking much about it, you copy that in. Later, people need their national tree and flower, so you add slots for them. Pretty soon everyone from Peru has identical copies of everything about Peru. Object oriented systems like to hide the exact way data is stored, making accidental copying even easier.

One of my favorite problems like this is instance vs. blueprint. Suppose a Robot class has current health, maximum health, engine type, percent power remaining, and so on. Seems fine, and it works, but half of those depend only on the type of robot. Robots could store just current health, power remaining, and a link to their type.

Chain of Responsibility

This means what it sounds like, but can be a little fuzzy in practice. It general it means a list of things to try, which was put together just for this program.

Some things it's not: a function is allowed to call another function, and so on. That's a chain, but it's just normal programming. Likewise a function might always try A, B, C then D and pick the first one that works. That's also just a normal function.

A chain of responsibility is more like a plug-in. If the function can't solve our problem, it checks to see if we gave it a back-up and tries that. The typical list of font-families that match the one we want less-and-less is sort of like this.

Bridge

This is another one that solves a specific Object Oriented problem. Suppose an airplane class has 3 options for engines, navigation, and what it's made of. Standard old-style OOP says you need 3x3x3 = 27 classes to hold every combination. Really. Names would be things like turboCompassSteelAirplane. It would inherit from turboCompassAirplane. Bridge says you can do it using base classes for each part:

class Airplane {
  GenericEngine engine; // base class for the 3 engine options
  GenericNavigation nav; // same
  GenericMaterial skinMetal; // same

Our turbo, compass, steel airplane now would be created starting with just an airplane, then making new TurboEngine() to plug into the engine variable, and so on. This is the normal way we do things now.

There a little bit of a trick here. We're assuming the parts are orthogonal - the way they work doesn't depend on what other parts are installed. That's how most things work, which means 27 airplane classes is a waste. If the engine works differently depending on the navigation and body type then we need to hand-write every combination.

The definition of a Bridge is "use an abstraction to decouple from the implementation". That could mean anything. But if you read the book where it explains it more, it's like the rewritten airplane.

Strategy

This is another word for using pointers to functions.

We can think of functions pointers in two ways. A callback is when we tell someone else what to do - a button calling OnButtonClick. A plug-in is when we ask someone else for help, so we can finish our job. There's no actual difference, but they feel different. Strategy is the word for a plug-in type function pointer. The idea is, suppose a monster is deciding who to attack. A function that rates each player could be plugged in, depending on the type of monster, to determine it's "strategy".

The OOP way of doing this is creating a class holding the function. that lets us bundle some variables with it. Our function can carry around some settings, or have a memory. If you haven't seen that trick it's kind of neat, but complicated:

Suppose we want functions that rates a string yes/no. We want to make several different types which can be plugged into a variable. We'll use a base class. All it does is establish the function signature:

abstract class nameChecker { // base class
  virtual bool checkName(string w);
}

The real class will inherit. This one will let you pre-set one letter which can't be in it. A function can't do that, since it has no way of saving the letter between uses, but a class can:

class notThisLetter : nameChecker {
  char wrongLetter;

  // constructor requires you give it the letter to skip:
  public notThisLetter(char notThis) { wrongLetter=notThis; }

  // reject words with the letter:
  virtual bool checkName(string w) {
    if(!w.contains(wrongLetter)) return true; // no bad letters
    return false;
  }
}

It gets plugged-in the same as a function would:

  nameChecker nc1; // someone will set this up  
  if(nc1.checkName("billy")) ...

  // elsewhere:
  nc1 = new notThisLetter('e'); // plug-in the test for names

Template

This is the same as strategy, except using inheritance on the whole thing to override parts. a class using plug-ins, then the same using overriden functions:

class doStuffWithStrategy {
  arrangerBase arranger; // plug in a function here
  selectorBase selector; // plug in a function here
    ...
}

We always use the doStuffWithStrategy class, with different items plugged in which we'll use at various steps. This rewrite changes the variables into virtual functions:

class doStuffWithTemplate {
  virtual void arranger() { ... } // standard way to arrange
  virtual void selector() { ... } // ditto
  
  void mainThing() {
    arranger();
    // more stuff
    selector();
  }
}

To change how we arrange or select, override in a base class:

class doStuff2 : doStuffWithTemplate {
  override void arranger() { ... } // different arranger code
}

When we run a copy of doStuff2 it runs the inherited mainThing, going through the normal steps, then using our new arranger, but the old selector since we didn't override it.

This is the standard way of doing "functional" inheritance. Sometimes we make a base class with empty functions to fill in. Sometimes we make a small one and subclasses add more stuff. This approach says to make a normal class that does everything you need, but make some parts virtual so they can be changed.

The book points out something else which is now completely standard: when you override a virtual function, sometimes it's a complete rewrite. And sometimes you call the original and just change it a little.

Mediator

This is another word for a manager or controller.

The interesting idea is it doesn't have to be for the entire program, like an old-style Controller. If you have a few parts that need to work together, but it's a pain having them all know about and talk to each other, you can make one special-purpose class that runs them all. It calls part A, passes the info to part B, and so on. The rest of the program only deals with that controller. But, really, you're simply making a new class using old ones, which is no big deal.

Memento

This is a very specific thing, and very minor, about making a system for undo's.

Suppose before every change you save the old values. To undo, restore the old saved ones. That's huge overkill, but it's simple and it works. Memento says to make the saved variables private, and create a save() and restore() function.

 

Summary

One way to use Design Patterns is to try to learn advanced programing. But after you get rid of the obsolete and extreme OOP ones, the rest are things which are covered better in a normal 2nd semester textbook. Reading Design Patterns after that is just awkward ways of re-describing what you already know.

The other way of using them is as a checklist. You get stuck, so pause to look through the list for ideas. But same problem. Half can be tossed. The rest are too vague, too specific, overlap in funny ways. They aren't actionable. Say you find 4 Design Patterns which might apply to your situation. They won't tell you what to actually do. They don't work in reverse, either. Take a well-designed bit of code and pick out the Design Patterns that were used. Seems like it would be a good way to remember it for later. But you can't. No one online can either. Everything that works for real is sort of this Design Pattern, but maybe more these two with a touch of that.

But that's not the fault of the authors. It was a perfectly good list of "here's what people are doing in the hot new field of OOP" back in the day.

I hope Design Patterns were good for one thing: a fun look at some of the history of computer science, the frustrating stop-and-start progress of Software Engineering, and the world of 2005 java programmers.

 

 

Comments. or email adminATtaxesforcatses.com