일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- input
- Kadane's Algorithm
- array
- 사칙연산
- 자바 thread 실행 순서 제어
- hash table
- 수학
- R
- 카데인 알고리즘
- scanner
- 자바입력
- Easy
- SpringBoot 2
- JAVA11
- 자바 스레드 실행 순서 제어
- heroku
- Today
- Total
DeFacto-Standard IT
Bridge Pattern (기본) 본문
1. 가정
- 아톰을 만든다.
- 아톰은 펀치공격이 가능하다.
2. Naive Code
- Punch
public class Punch {
private final String attackType = "Punch";
public String getName() {
return attackType;
}
}
펀치 공격에 해당하는 클래스.
- Atom
public class Atom {
private final String robotType = "Atom";
private Punch punch;
public void setPunch(Punch punch) {
this.punch = punch;
}
public void attack() {
System.out.println(robotType + " : " + punch.getName());
}
}
아톰에 해당하는 클래스이다.
- NaiveClient
public class NaiveClient {
public static void main(String args[]) {
Punch punch = new Punch();
Atom atom = new Atom();
atom.setPunch(punch);
atom.attack();
}
}
실행 결과는 다음과 같다.
3. 문제점
위 소스코드는 Atom이라는 로봇이 Punch공격을 하는 소스코드이다.
만약 다음과 같은 요구사항의 변경이 발생했다고 가정해보자.
- 로봇의 종류는 Atom뿐만 아니라, MazingerZ, TaekwonV가 추가된다.
- 공격의 종류는 Punch뿐만 아니라, Missle, Kick이 추가된다.
첫 번째 요구사항을 충족하기 위해서는, MazingerZ, TaekwonV라는 로봇클래스가 추가되어야 한다.
두 번째 요구사항을 충족하기 위해서는, 로봇들과 마찬가지로 Missile, Kick 클래스가 추가되어야 한다.
세 번째 요구사항을 충족하기 위해서는, NaiveClient의 ADriver객체를 BDriver객체로 바꾸어야 한다. 또한, Taxi의 ADriver 타입을 BDriver타입으로 변경해야한다.
문제는, 이러한 사항은 요구사항이 변경될 때 마다 계속해서 바뀐다는 것이다.
4. 해결방안
위와 같은 문제는, 2가지에 의해 발생한다.
1. Client에서 Atom이라는 구체적인 타입에 대한 객체를 사용한다.
2. Atom에서 Punch라는 구체적인 타입에 대한 객체를 사용한다.
위 두가지는 모두 '결합도가 높다'는 것을 의미한다.
따라서, 결합도를 낮추어 위와 같은 문제가 발생했을 때, 기존 소스코드의 변경을 최소화해야 한다.
Atom, MazingerZ, TaekwonV는 공통적으로 로봇이라고 칭할 수 있다. 따라서, Robot이라는 추상클래스를 통해 추상화하면 된다.
이렇게 한다면, 어떤 종류의 로봇이 오든, Client는 알 필요가 없다.
Punch, Missile, Kick 역시 마찬가지이다. Attack이라 추상적인 개념을 만들고 다루어야 한다.
이렇게 한다면 결합도가 낮아지기 때문에, 어떤 Robot이 오든, 어떤 Attack이 오든 상관없어진다.
5. Solution Code
- Implementor
public interface Implementor {
public void implementation();
}
구현부에 대한 인터페이스이다. 예제에서는 Attack에 해당한다.
- ConcreteImplementor1, 2
public class ConcreteImplementor1 implements Implementor { |
public class ConcreteImplementor2 implements Implementor { |
구체적인 구현부이다. 인터페이스를 통해 이를 사용하는 Abstraction과의 결합도가 감소한다.
예제에서는 Punch, Missile, Kick에 해당한다.
- Abstraction
public abstract class Abstraction {
protected Implementor implementor;
public void setImplementor(Implementor implementor) {
this.implementor = implementor;
}
public abstract void doAbstraction();
}
추상적인 개념이다. 예제에서는 Robot에 해당한다.
- RefinedAbstraction
public class RefinedAbstraction1 extends Abstraction { |
public class RefinedAbstraction2 extends Abstraction { |
구체적인 로봇 클래스이다. 예제에서는 Atom, MazingerZ, TaekwonV에 해당한다.
- Client
public class Client {
public static void main(String args[]) {
Abstraction abstraction1 = new RefinedAbstraction1();
Implementor implementor1 = new ConcreteImplementor1();
abstraction1.setImplementor(implementor1);
abstraction1.doAbstraction();
Abstraction abstraction2 = new RefinedAbstraction2();
Implementor implementor2 = new ConcreteImplementor2();
abstraction2.setImplementor(implementor2);
abstraction2.doAbstraction();
}
}
실행 결과는 다음과 같다.
6. Bridge Pattern
Bridge Pattern은 구현부와 추상층을 분리하여 클래스간의 결합도를 낮추고, 다형성을 구현하도록 한다.
Bridge Pattern을 적용하기 전의 클래스 호출의 방향성은
Client -> Concrete Class -> Concrete Class 의 순서였다.
여기에 Bridge Pattern을 적용한 후에는
Client -> Abstract Class -> Concerete Class -> Interface Class -> Implementation Class
와 같은 흐름이 될 것이다.
Abstract Class, Interface Class등 추상적인 개념은 일종의 중간다리 역할을 하는 것이다.
OOP에서 '다형성'을 구현하기 위한 기본적인 패턴이다.
Bridge Pattern과 Strategy Pattern은 Class Diagram, 즉 구현 자체는 거의 일치하지만, '의도'가 다르다.
Bridge Pattern
- 구현부와 추상층으로 분리하여 서로가 다르게 동작할 수 있게 한다.
- 상속계층에 인터페이스를 두고, 이 상속계층에 구현부를 포함시킨다.
- Structural Pattern이다.
- 추상화와 구현이 컴파일 타임에 결정되지 않을 때 사용
- 추상화 및 구현은 독립적으로 변경되어야 할 때 사용
- 추상화 구현 변경으로 인해 Client에 영향을 미치지 않아야 할 때 사용
- Client는 구현 세부 사항으로부터 격리되어야 할 때 사용
Strategy Pattern
- 알고리즘 집단을 정의하고, 각각을 캡슐화 하여 상호교환하여 시시각각 바꿀 수 있게 한다.
- 알고리즘과 이를 사용하는 Client의 결합도를 낮춘다.
- 인터페이스를 통해 알고리즘을 추상화하고, 이를 구현하는 클래스에서 알고리즘을 구체화 한다.
- Behavioral Pattern이다.
- 여러 버전의 알고리즘이 필요할 때 사용
- 런타임에 클래스의 동작을 동적으로 변경해야 할 때 사용
- 조건문을 피해야 할 때 사용
어떻게 보면, Bridge Pattern은 Strategy Pattern에 포함된다고 볼 수 있다.
'행동'이라는 것은 하나의 동작을 진행할 때 런타임 시점에서 사용자가 알맞는 알고리즘등을 선택하여 진행하는 것이다.
'구조'라는 것은 인터페이스의 구조를 나누고 추상적인 참조를 통해 합치는 의미이다.
- UML & Sequence Diagram
- Class Diagram
7. 장단점
장점 :
단점 :
'Design Pattern > Structural Pattern' 카테고리의 다른 글
Flyweight Pattern (0) | 2018.02.16 |
---|---|
Facade Pattern (기본) (4) | 2018.02.16 |
Adapter Pattern (0) | 2018.02.16 |
Proxy Pattern (0) | 2018.02.16 |
Composite Pattern (0) | 2017.09.26 |