Design Patterns
1. State
'State' Pattern is used to implement 'Finite State Model' of discrete mathematics. Finite State Model is a model that has
1. finite numbers of states
2. there are available actions for each states and state changes through those actions.
For example, we can have an example like 'Aegislash' of Pokemon. Aegislash is a Pokemon that its form changes with its move. It has two different forms, swords form and shield form, and let's suppose that it has three different moves: swords dance, king shield, and shadow claw.To implement this pattern, you have look into 3 different steps.
1. make an interface for the 'State' having corresponding methods for each action.
interface AegislashForm()
{
void swords_dance();
void king_shield();
void shadow_claw();
}
2. make each specific 'State' implement the the interface of 'State' of 1. Each state should have the entity(the machine) as its attribute, and have to override(implement) the methods of 1.
class SwordForm implements AegislashForm()
{
public SwordForm(Aegislash aegislash)
{
this.aegislash = aegislash
}
@override
public swordsDance()
{
pass
}
public kingShield()
{
aegislash.attack -= 10
aegislash.armor += 10
aegislash.aegislashForm = aegislash.shieldForm
}
public shadowClaw()
{
pass
}
}
class ShieldForm implements AegislashForm()
{
public ShieldForm(Aegislash aegislash)
{
this.aegislash = aegislash
}
@override
public swordsDance()
{
pass
}
public kingShield()
{
pass
}
public shadowClaw()
{
aegislash.attack += 10
aegislash.armor -= 10
aegislash.aegislashForm = aegislash.swordForm
}
}
3. make the actual 'Machine' that corresponds to the machine. Machine should have every state that it can have and its current state as its attribute, and have methods same with the 'State' interface so that it can run it by calling the current state's method. Also, the point is that the 'states' should do nothing but overriding the methods. If they have other attributes, the responsibility can be ruined. For example,
class Aegislash
{
public AegislashForm shieldForm
public AegislashForm swordForm
public Aegislash()
{
this.shieldForm = new ShieldForm(this)
this.swordForm = new SwordForm(this)
}
private AegislashForm aegislashForm
private int attack
private int armor
public void swordsDance()
{
aegislashForm.swordsDance();
}
public void kingShield()
{
aegislashForm.kingShield();
}
public void shadowClaw()
{
aegislashForm.shadowClaw();
}
}
how about state-dependent-action? For example, what if action shadowClaw() isnt available when in shieldForm? In this case, you just might define the method that throws error. like
public shadowClaw()
{
throw new ImpossibleActionException}
Then, how can we make the attributes rely on the 'states' themselves? For example, you wanna make aegislash.attack = 0 when 'shieldForm' whatever their previous form was. In this case, you can make a method like 'enterState' and override it that it can make aegislash.attack = 0 when they enter the state. i.e,
class ShieldForm implements AegislashForm()
{
public ShieldForm(Aegislash aegislash)
{
this.aegislash = aegislash
}
@override
public swordsDance()
{
pass
}
public kingShield()
{
pass
}
public shadowClaw()
{
aegislash.aegislashForm = aegislash.swordForm
aegislash.aegislashForm.enterState();
}
Note that this can be useful in n:1 relationship(Multiple object can do same thing to object of another type, but behaves differently.
2. Strategy
Strategy pattern and state pattern is very similar.
'Strategy' Pattern is very frequently used pattern so you should be aware of it. The point of the strategy pattern is, it makes all of actions that the classes are capable of into strategy and wraps it with interface.
For example, let's suppose that the client is a car driver and he tries to make a use of different type of cars. sedan, truck and bus are all construction machine, but they have lots of differences in their driving. How can you deal with it?
1. make all the available behaviors(in the perspective of the client) into interface. Those interfaces supposedly consists of just one method.
public interface IBrakeBehavior
{
public void brake
}
public interface IAccelBehavior
{
public void drive
}
2. make the implementations of the interfaces of 1., which is the all available actions in perspective of the classes. These are called 'Strategy'. The point is, the method of the class that implements the same behavior should have the same name.
public class DiskBrake implements IBrakeBehavior
{
public void brake(){ diskbrake... }
}
public class AirBrake implements IBrakeBehavior
{
public void brake(){ airbrake... }
}
public class Accel implements IAccelBehavior
{
public void accel(){ accelerate.. }
}
3. make the abstract class which is the mother of all the classes. It has attribute of instances of all of the behaviors of 1. and method to trigger it.
public class Car
{
public IBrakeBehavior iBrakeStrategy
public IAccelBehavior iAccelStrategy
public void brake
{
iBrakeStrategy.brake
}
public void accel
{
iAccelStrategy.accel
}
}
4. make the types of classes to inherit the class of 3. The classes should have the attributes(the behaviors) initialized to have the ones relevant to themselves.
public class sedan extends Car
{
public IBrakeBehavior iBrakeStrategy = new DiskBrake()
public IAccelBehavior iAccelStrategy = new Accel()
}
public class sedan extends Truck
{
public IBrakeBehavior iBrakeStrategy = new AirBrake()
public IAccelBehavior iAccelStrategy = new Accel()
}
5. Make the client. Client should have instances of all the classes of 4. and the currently used type as its attribute. Client should be also able to 'do' the behaviors of 1.
public class Driver
{
public Sedan sedan
public Truck truck
public Bus bus
public Driver()
{
sedan = new sedan()
truck = new truck()
bus = new bus()
current_car = sedan
}
public void accel()
{
current_car.accel()
}
public void brake()
{
current_car.brake()
}
}
3. Builder
Builder is a design pattern that hides the constructor of the target class and uses inner class called 'builder' instead.
For example, when you try to make a class 'Human' like
class Human()
{
private age
private sex
public Human(age, sex){ this.age = age; this.sex = sex }
}
you can write like
class Human
{
private age
private sex
Human(age, sex){ this.age = age; this.sex = sex }
public static class Builder
{
private age
private sex
public Builder():
publicBuilder setAge(age) {this.age; return this;};
public setSex(age) {this.sex = sex; return this;};
public Human build() { return Human(this.age, this.sex); )
}
}
So you can construct Human like
Human human = new Human.Builder().setAge(23).setSex('M').build()
instead of
Human human = new Human(23, 'M')
You should know that setX methods should return the value like return this; not just setting the attribute using this.x = X
Seems like code became much longer!! Why should we use the builder pattern then? There are 2 reasons.
1. you don't have to be given all the parameters.
Suppose that you want to give only sex as the parameter and set age as 20.
Human human = new Human('M')
the above code isn't possible in Java. So you can write instead
public static class Builder
{
private age = 20;
private sex;
public Builder():
public Builder setAge(age) {this.age; return this;};
public setSex(age) {this.sex = sex; return this;};
public Human build() { return Human(this.age, this.sex); )
}
}
then you can use this like
new Human.Builder().setSex('M').build()
to construct Human(20, 'M')
2. to name the parameters.
If there are like 10+ parameters, it would be very hard to remember the order of the parameters. Instead builder does the same work like
new Human.Builder().setAge(23).setSex('M').build()
== new Human.Builder().setSex('M').setAge(23).build()
So you don't have to remember the order.
For me, this looks like very inefficient substitute for the 'Default Parameter' of Python. In Python you can define constructor like
Human(sex = 20, age = 'M')
human = Human(age = 'F')
and the language constructs the human as sex = 20 and age = 'F'. Guess there is a lombok annotation that enables this with much shorter code.
4. Static Factory Method Pattern.
Static Factory Method Pattern is very similar to the Builder Pattern, but let's take a look at it.
1.
It's first advantage is that you can set the name of it like
public static Person nameAndHeightOf(String name, Double height)You can explicitly show the parameters using methods like the above.2.It's second advantage is that you can set you can use the prototype or singleton pattern to save the cost.3.It's third advantage is that you can return different classes by the parameters given.public static HumanFactory{public static Human makeHumanByAge(int age){if (age > 18){return new Adult(age);}else{return new Kid(age);}}}Just like the above you can choose the type of the return dynamically.
4.
You can hide the actual type of the return. In code of the 3, you don't have to reveal the definition or even existence of the class Adult or Kid. You can just reveal the return type(which would be the parent class or abstract class or interface).
5.
You don't have to define the return type when you define the static factory. In code of the 3, you don't have to define Adult or Kid. Let's suppose that you know that the service logic for kid and the adult would be different, but now there are only members with age over 20 in the database. You can make makeHumanByAge(int age) in advance, but you can define class Kid later when you have the kid members.
Static Factory Method Pattern has naming conventions.
1. from: returns instance of the type with a parameter given.
2. of: returns instance of the type with several parameters given.
3. valueOf: similar to from/of
4. instance, getInstance: returns an instance, but it might not be a new instance; using advantage no.2
5. create, newInstance: Always returns a new instance
6. getType: similar to getInstance, but the type of Instance is different from the factory. Type is the return type.
i.e.
Human human = Human.getInstance();
Human human = AnimalFactory.getHuman();
7. newType: similar to newInstance, but the type of instance is different from the factory. Type is the return type.
8. type: similar to getType, returnType.
4. Factory method
Factory method's bit similar to the builder. Instead, it defines 'factory' method in the parent class and defers which instance to be constructed to its subclasses. It is used when one class has a role to create instances of other classes.
Let's take a further look. Let's suppose that there is a pizzeria.
class pizzeria
{
public pizzeria()
public sellPizza()
{
Pizza pizza = new Pizza()
pizza.cut()
pizza.pack()
pizza.deliver()
return pizza
}
}
the above code depends on class called Pizza, it isn't desirable in terms of OOP. How can we improve it?
class pizzeria
{
public pizzeria()
public sellPizza()
{
Pizza pizza = createPizza()
pizza.cut()
pizza.pack()
pizza.deliver()
return pizza
}
public Pizza createPizza()
{
return new Pizza()
}
}
We segregated creating an instance of Pizza into another method createPizza(). Still, it does depend on the class Pizza. How can we eliminate such dependency? We can defer the object's creation to a subclass's factory method.
class pizzeria
{
public pizzeria()
public sellPizza()
{
Pizza pizza = createPizza()
pizza.cut()
pizza.pack()
pizza.deliver()
return pizza
}
abstract protected Pizza pizzaFactory();
}
Let's suppose there is a 'class PeperoniPizza extends Pizza'. Then we can define PeperoniPizzeria like
class PeperoniPizzeria extends Pizzeria
{
@override
protected Pizza pizzaFactory() { return new PeperoniPizza(); }
}
It has much longer code than it had before, but it enables us SOLID. The client(pizzeria in the above example) does not have to depend on concrete class, and thus it has no need to be modified for changes like additional pizza types.
4. Prototype
'Prototype' Pattern is used to clone a single instance, so that it can reduce a cost of creating a new instance(i.e. if instance creation requires DB access). Let's take a look at it. Let's suppose that
class Pizza implements Cloneable
{
public Object Clone()
{
try:
Pizza copiedPizza = (Pizza)super.clone();
return copiedPizza
}
class Pizzeria
{
private Pizza pizza;
public Pizzeria() { this.pizza = new Pizza(); }
public Pizza pizzaCopy()
{
return pizza.clone();
}
}
You can also defer the definition of the clone() into concrete classes of Pizza: using 'template method pattern'. @override public Object clone();
5. Singleton Pattern
The 'Singleton Pattern' is used to make sure there is only one instance of the class. It hides constructor and instead uses method getInstance(). It has two different implementations
5-1. Eager Initialization
This implementation creates an instance when loading the class. So actual implementation would look like
class Printer
{
private Boolean Printer_Using = False;
static final Printer instance = new Printer();
private Printer() { ... }
public static getInstance() { return instance; }
}
5-2 Lazy Initialization
This implementation creates an instance when the instance is actually called. Thus, it can save memory, but sometimes causes multiple instances error. So actual implementation would look like
class Printer
{
private Boolean Printer_Using = False;
private static Singleton instance;
private Printer() { ... }
public static getInstance()
{
if instance == NULL:
instance = new Singleton();
else:
return Instance;
}
}
However, using singleton Pattern is not always useful. It is useful in situations meeting below conditions.
1. Class has no attribute. Or none of the attributes are modifiable.
2. Class has more than one instance methods.
Such situations are rare. In most cases, using static classes would be more useful.
6. Abstract Factory Pattern
Unlike Factory Method pattern, Abstract Factory is a different class from the client. When a client needs concrete Products like ProductA and ProductB, the client refers to the interface Abstract Factory. There is a concrete class of Abstract Factory like ConcreteFactory. ConcreteFactory creates an object of ProductA and ProductB in their concrete implementations like ProductA1, ProductB1. Abstract Factory has methods that create objects like createProductA or createProductB. For example,
interface Pizza {}
interface Beverage {}
class PeperoniPizza {}
class Coke {}
class CheesePizza {}
class Sprite {}
interface AbstractPizzaFactory
{
public Pizza makePizza
public Beverage makeBeverage
}
class PeperoniPizzaFactory
{
@override
public Pizza makePizza
{
return new PeperoniPizza
}
public Beverage makeBeverage
{
return new Coke
}
}
Like the above code, which concrete product will be created are defined by the definition of the class ConcreteFactory. The point is, the client does not know which concrete Product would be injected. It can only see the interface.
Then what's the difference between the factory method pattern? This might not be true, but abstract factory seems like it segregated the 'Object creation' part into another interface. Factory Method pattern segregated the object creation into another 'method' and defers its actual implementation into its subclasses. So, the client(final client) sees the class or subclass(of the 'Creator'). If creation of another object is needed, injection of the subclass(of the creator) should be replaced. However, when using Abstract Factory Pattern, if another creation is needed, injection of the concrete factory(into the 'Creator) should be replaced.
So when the client(uses Pizzeria, the creator) wants cheese pizza instead of peperoni pizza, Factory Method pattern would replace PeperoniPizzeria(subclass of the creator) with CheesePizzeria, while Abstract Factory pattern wouldn't touch the Pizzeria(the creator) and replace PeperoniPizzaFactory(factory class which is injected into creator) into CheesePizzaFactory so that Pizzeria can make a cheese pizza. I think this difference comes from the point that Pizzeria of the Factory Method pattern has methods of createPizza and all the other operations, while Abstract Factory segregated responsibility of creatingPizza into different class called PizzaFactory. Factory Method segregates creation into another 'method' while Abstract Factory segregates into another 'class'.
The above example was about making an abstract factory by inheritance(subclassing). You can make an abstract factory by composition: delegation pattern and prototype pattern. In this case, it would look like
interface AbstractPizzaFactory
{
public Pizza makePizza
public Beverage makeBeverage
}
class ConcretePizzaFactory
{
public ConcretePizzaFactory(Pizza pizzaPrototype, Beverage beveragePrototype)
{
this.pizza = pizza;
this.beverage = beverage;
}
@override
public Pizza makePizza
{
return pizzaPrototype.clone();
}
public Beverage makeBeverage
{
return beveragePrototype.clone();
}
}
7. Adapter
Adapter Pattern is used to make the client can use the interface that it does not conform to. It is used to make existing class work with some other class without modifying the class. It can be classified into 'Object Adapter Pattern' and 'Class Adapater Pattern'

The difference is how the adapter uses the specific Operation. The 'Object Adapter' uses specific Operation by 'Delegate Pattern'. It has adaptee as an attribute and calls it, while Class Adapter inherits the Adaptee and uses its specificOperation.
When Target is not an interface but a class, Class adapter needs to inherit two different adaptees, which might make class adapter unavailable in Java.
Adapter is usually named like '[ClassName]To[Interface]Adapter'.For example, the client uses an interface called 'Circle'
interface Circle
{
public int getPerimeter();
public int getArea();
}
class CircleImpl()
{
}
When we want to enable the client to use the Square, we can make SquareToCircleAdapter
class SquareToCircleAdapter implements Circle
{
Square sqaure;
public SquareToCircleAdapter(Square square) { this.square = square; }
@override
public int getPerimeter()
{
return 4 * square.getSideLength();
}
public int getArea()
{
sideLength = square.getSideLength();
return sideLength * sideLength;
}
}
Defining adapter like the above, the client can use Square like Circle. The above would be object adapter and the class adapter would look like
public SquareToCircleAdapter extends Square implements Circle
{
@override
public int getPerimeter()
{
return 4 * getSideLength();
}
public int getArea()
{
sideLength = getSideLength();
return sideLength * sideLength;
}
}
8. Composite
'Composite' Pattern is a pattern that enables the client to handle 'part' and the 'whole' in the same way. This might not be understood intuitively. If there is a group of a part called 'A', when you do some operation that does something to the part to the 'A', it does operation all the thing to the parts included in 'A', with the same method of the client. For example,
'Directory' is a group of 'File's. In this case, 'Directory' is a 'Composite' and 'File' is a 'Leaf'('Leaf' should be the primary unit, which cannot be decomposed more). And we call the group including both of them 'Component'. So it would be like
@Component
interface FileSystemComponent
{
public void clone();
public FileSystemComponent copy();
public void rename();
}
Component should have methods that are operated uniformly in both the directory and the composite.
@Leaf
class File implements FileSystemComponent
{
}
@Composite
class Directory Implements FileSystemComponent
{
}
So you can use methods like clone(), copy(), rename() whatever you chose is a single 'File' or a 'Directory' filled with several files. Also, you should consider 'Recursive Inclusion' when defining the methods of the Composite.(i.e. you should regard that the Directory can include not only file, but also other directories)
There are two different types of actual implementation of this code.
As you can see, the difference is whether the methods of composite pattern handling the child are included in the Component or not.
In the left one, Component's method would be (Leaf's methods) ∪ (Composite's methods). The advantage of this way is that the client never faces the leaf and the composite. Component can do everything their implementations can do, so Client can only face the Component. The problem is, you can see that the Leaf does not have the 'child method's. This can result in error.
In the right one, Component's method would be (Leaf's methods) ∩ (Composite's methods). The advantage of this way is that Both the leaf and the composite have the full implementation of the Component, so there would be No type error. The disadvantage is, the component does not have access to the 'child function's when facing the component, so it needs another way to use them.
You can instead use right one + template method for the composite.
9. Bridge Pattern
Bridge Pattern is utilizing 'Delegate' pattern to use two different hierarchies in one class. For example, "Lion" is a subclass of "Animal". It would look like
class Lion extends Animal
{
public Lion() { ... }
@override
public move() { ... }
@override
public breathe() { ... }
}
However, let's say there are some other classes like "Snake", "Shark" and "Whale". Tiger and Lion are both land animals. You can make a inheritance hierarchy like
Animal
LandAnimal SeaAnimal
Lion Tiger Shark Whale
But, you can use composition instead of inheritance. Then, you can segregate the method's implementation outside of the class. In this case, let's suppose that land animals only share the breathe() method. Then you can make it like
interface BreatheHandler()
{
public void breathe();
}
class LandBreatheHandler()
{
@override
public void breathe()
{
//breathe with lung
}
}
and you can make Animal and Lion like
abstract class Animal
{
protected BreatheHandler breatheHandler;
public Animal(BreatheHandler breatheHandler) { this.breatheHandelr = breatheHandler; }
...
public abstract breathe();
}
class Lion extends Animal
{
public Lion(BreatheHandler breatheHandler) { super(breatheHandler); }
@override
public void breathe() { breatheHandler.breathe(); }
}
+ you can just make the class depend on the Handler like
public Lion() { super(new LungBreatheHandler()); }
if you need or want.
More amazing point is that, there is no need for 2 hierarchies to have any relationship. So instead of 'Animal Species' category and 'Land/Sea' category, you can use 'Animal Species' category and 'Sex' category. You can thus make female lion like using interface SexHandler, class FemaleHandler and femaleLion = new Lion(femaleHandler);.
10. Delegate Pattern
Delegate Pattern is a key of 'composition over inheritance'. It uses internal object to use some its methods. The point is that the delegate does 'just the same thing' as its object instead of inheritance.
For example
class Animal
{
public void bark();
}
class Dog extends Animal
{
@override
public void bark() { return "DogDog"; }
}
when you wanna change bark() method of the Animal into speak() method, you have to change all the dog.bark() to dog.speak. However,
class Dog
{
private Animal animal
public Dog(Animal animal)
{
this.animal = animal;
}
public void bark() { return animal.bark(); }
}
when you wanna change bark() method to speak() method, you can just change the bold code into
animal.speak(). This reduces the dependency.
11. Facade Pattern
Facade pattern enables the client to use other subsystem's function without knowing the internal situation. For example, let's suppose that you are trying to drive a car. Actually, your car goes through complex process to get started. It first turns on the electronic system, and the system activates the power train systems like ignition or fueling. Then, the start motor runs the engine and the ignition plug ignites the fuel in the engine. When the ignition is on and engine can run itself, turns off the start motor. Very complicated huh? However, you don't need to go through all the steps to drive your car. In fact, even knowing such steps are unnecessary, because the car manufacturer made the engine starting system so that you can just press the 'engine start button' and all the steps are done. Facade pattern is like the 'engine starting system'. All the client needs to do is to press the 'engine start button'. You don't need to know the process. Even if the process changes because the car's power train has changed into diesel engine or electronic motor. What client should know is that the engine starts, when you press the button. Let's take a look at the pattern.
class ICEngineStartingSystem implements EngineStartingSystem()
{
private electronicSystem
private powerSystem
private startMotor
private igniter
public EngineStartingSystem()
{
this.electronicSystem = new ElectronicSystem()
this.powerSystem = new PowerSystem()
this.startMotor = new StartMotor()
this.igniter = new Igniter()
}
public void EngineStart()
{
electronicSystem.on();
powerSystem.on(electronicSystem);
startMotor.on();
igniter.igniteEngine();
startMotor.off();
}
}
using the method EngineStart(), the client does not have to use all the codes of
electronicSystem.on();
powerSystem.on(electronicSystem);
startMotor.on();
igniter.igniteEngine();
startMotor.off();
Also the good point is that when the EngineStartingSystem needs to be changed because the car has changed into an electronic car, you can just change the ICEngineStartingSystem into ElectricMotorStartingSystem.(Or you can implement the 'Abstract Factory' or 'Factory Method' pattern into the ICEngineStartingSystem and change for a small modification like electronic system change, not a total change)
12. Decorater Pattern
'Decorater' pattern is a pattern used to grant an object additional behaviors. It is used to add an object additional behavior in 'Runtime' in contrast to inheritance which adds additional behavior in Compile time. It has a structure like
![]()
You might not be able to understand it easily. Let's look at the example.
You have a class like
public interface Car();
class CarImpl implements car
{
private int carSpeed;
public car(); { }
public void drive(); {}
}
You want to make a car with a trunk, and it would be a bit slower because it got heavy.
public abstract class CarDecorator implements car
{
private final Car decoratedCar;
public CarDecorater(Car car) { this.decoratedCar = car }
@override
public abstract void drive(); {}
}
public CarTrunkDecorater extends CarDecorater
{
private int loadWeight;
public CarTrunkDecorater(Car car, Int loadWeight) { super(car); this.loadWeight = loadWeight; }
public void drive(); { //drive slowly depending on the loadWeight }
}
With the above code, you can load 8kgs of luggage like
Car Truck = new CarImpl();
Truck = new CarTrunkDecorater(Truck, 8);
Truck.drive();
13. FlyWeight Pattern
FlyWeight Pattern enables similar objects to share data, so that they can save the memory.
To apply FlyWeight Pattern, you need to segregate 'instrinsic' state and 'extrinsic' state.
Intrinsic State: invariant, context-independent and thus shareable...
This can be better in some context. However, the major advantage of flyweight pattern over "abstract class + static field" is that you can create intrinsic state dynamically(at runtime). Static fields can be only assigned at compile time.

댓글
댓글 쓰기