Design Patterns

What are Design Patterns?

In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. A design pattern is not a finished design that can be transformed directly into source or machine code. It is a description or template for how to solve a problem that can be used in many different situations.

Strategy Pattern

Now, you're going to design a RPG game again!

class Warrior {
    private String name;
    public Warrior(String userName){
        name = userName;
    }
    public void run(){
        System.out.println("run");
    }
    public void fight(){
        System.out.println("brandish");
    }
}

Warrior Class

class Magician {
    private String name;
    public Magician(String userName){
        name = userName;
    }
    public void run(){
        System.out.println("run");
    }
    public void fight(){
        System.out.println("cast");
    }
}

Magician Class

OO Principle: Encapsulate what varies.

class Character{
    protected String name;
    public Character(String userName){
        name = userName;
    }
    protected void run(){
        System.out.println("run");
    }
    public void fight(){}
}
class Warrior extends Character{
    public Warrior(String username){
        super(username);
    }
    public void fight(){
        System.out.println("brandish");
    }
}
class Magician extends Character{
    public Magician(String username){
        super(username);
    }
    public void fight(){
        System.out.println("cast");
    }
}

What if you want to add a swordsman, a priest...

or worse, maybe a peasant? 

But something went wrong...

For swordsman, or priest, you need to overwrite every fight() method.  In other word, you need to do IT every time you create a new character.

But for peasant, you cannot even extends Character class.

But peasant can still run!!!

interface FightBehavior{
    public void fight();
}

And then, who is going to implement it?

Let's apply our Strategy Pattern

class FightWithSword implements FightBehavior {
    public void fight() {
        System.out.println("brandish");
    }
}
class FightWithMagic implements FightBehavior {
    public void fight() {
        System.out.println("cast");
    }
}
class Warrior extends Character{
    private FightWithSword fm;
    public Warrior(String username){
        super(username);
        fm= new FightWithSword();
        fm.fight();
    }
}

What if the warrior want to use knife?

FightBehavior fm = new fightWithSword();
//and the warrior want to use knife
fm = new fightWithKnife(); 

OO Principle: 

Program to interface, not an implementation.

class Character{
    protected String name;
    protected FightBehavior fm;
    public Character(String userName){
       name = userName;
    }
    public void run(){
        System.out.println("run");
    }
    protected void useWeapon(){
        fm.fight(name);
    }
}
interface FightBehavior{
    public void fight();
}
class FightWithSword implements FightBehavior{
    public void fight(){
        System.out.println("brandish");
    }
}
class FightWithMagic implements FightBehavior{
    public void fight(){
        System.out.println("cast");
    }
}
class SwordsMan extends Character{
    public SwordsMan(String username){
        super(username);
        fm = new FightWithSword();
    }
    
}
class Magician extends Character{
    public Magician(String username){
        super(username);
        fm = new FightWithMagic();
    }
    
}
class TestJava { 
    public static void main(String[] args){
        SwordsMan swordMan = new SwordsMan("John");
        Magician magician = new Magician("Mary");
        swordMan.run();
        magician.useWeapon();
        swordMan.useWeapon();
    }
}

Our final RPG

Strategy Pattern Defined

The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

OO Principles

Encapsulate what varies.

Favor composition over inheritance.

Program to interfaces, not implementation.

Singleton Pattern

public class Singleton{
    private static Singleton uniqueInstance;

    private Singleton(){}

    public static Singleton getInstance(){
        if (uniqueInstance == null)
            uniqueInstance = new Singleton();
    
        return uniqueInstance;
    }
}

Our constructor is declared private; only Singleton can instantiate this class!

We have a static variable to hold our one instance of the class Singleton.

The getInstance() method gives us a way to instantiate the class and also return am instance of it.

Chocolate Boiler

public class ChocolateBoiler {
    private boolean empty;
    private boolean boiled;

    public ChocolateBoiler() {
        empty = true;
        boiled = false;
    }

    public void fill() {
        if(isEmpty()) {
            empty = false;
            boiled = false;
            //fill the boiler with milk/chocolate mixture.
        }
    }

    public void drain() {
        if(!isEmpty() && isBoiled()) {
            // drain the boiled milk and chocolate.
            empty = true;
        }
    }

    public void boil() {
        if(!isEmpty() && !isBoiled()) {
            //bring a contents to a boil
            boil = true;
        }
    }

    public boolean isEmpty() {
        return empty;
    }

    public boolean isBoiled() {
        return boiled;
    }
}

We don't want more than one instance of ChocolateBoiler be created....

But the question is....

public class ChocolateBoiler {
    private boolean empty;
    private boolean boiled;

    private static ChocolateBoiler uniqueInstance;

    private public ChocolateBoiler() {
        empty = true;
        boiled = false;
    }

    //
    public static ChocolateBoiler getInstance() {
        if(uniqueInstance == null) {
            uniqueInstance = new ChocolateBoiler();
        }
        return uniqueInstance;
    }

   public void fill() {
        if(isEmpty()) {
            empty = false;
            boiled = false;
            //fill the boiler with milk/chocolate mixture.
        }
    }

    public void drain() {
        if(!isEmpty() && isBoiled()) {
            // drain the boiled milk and chocolate.
            empty = true;
        }
    }

    public void boil() {
        if(!isEmpty() && !isBoiled()) {
            //bring a contents to a boil
            boil = true;
        }
    }

    public boolean isEmpty() {
        return empty;
    }

    public boolean isBoiled() {
        return boiled;
    }
}

static variable to hold our one instance.

Constructor is declared private.

The getInstance() method gives us a way to instantiate the class and also return am instance of it.

Somehow the ChocolateBoiler method was able to start filling the boiler even though a batch of milk and chocolate was already boiling! 

But wait...

What Happened exactly?

Be the JVM

Thread 1

Thread 2

Value of uniqueInstance

public static ChocolateBoiler getInstance() {

if ( uniqueInstance == null ) {

uniqueInstance = new ChocolateBoiler();

return uniqueInstance;

null

<object1>

public static ChocolateBoiler getInstance() {

if ( uniqueInstance == null ) {

uniqueInstance = new ChocolateBoiler();

return uniqueInstance;

null

null

Oops!

<object2>

null

1. Add synchronized modifier.

2. Move to  an eagerly created instance rather than a lazily created one.

3. Use "double-checked locking" to reduce the use of synchronization in getInstance().

Can we improve multithreading?

straightforward and but ineffective.

synchronizing a method can decrease performance by a factor of 100.

Add synchronized modifier

public static synchronized ChocolateBoiler getInstance() {
    if(uniqueInstance == null) {
        uniqueInstance = new ChocolateBoiler();
    }
    return uniqueInstance;
}
public class Singleton {
    private static Singleton uniqueInstance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return uniqueInstance;
    }
}

Go ahead and create an instance of Singleton in a static  initializer.

We've already got a instance, so just return it.

Eagerly created instance

public class Singleton {
    private volatile static Singleton uniqueInstance;

    private Singleton() {}

    public static Singleton getInstance() {
        if( uniqueInstance == null ) {
            synchronized (Singleton.class) {
                if(uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

The volatile keyword ensures that multiple threads handle the uniqueInstance variable correctly when it is being initialized to the Singleton instance.

Note we only synchronize the first time through!

Double-Checked Locking

Singleton Pattern Defined

The Singleton Pattern ensures a class has only one instance, and provides a global point of access to it.

Design Patterns

By TingSheng Lee

Design Patterns

  • 257