Design Pattern : 행동 패턴(Behavioral Patterns) 2
6. 전략 패턴 (Strategy Pattern)
- 전략 패턴이란?
행위를 클래스로 캡슐화해 동적으로 행위를 자유롭게 바꿀 수 있게 해주는 패턴으로 같은 문제를 해결하는 여러 알고리즘이 클래스별로 캡슐화되어 있고 이들이 필요할 때 교체할 수 있도록 함으로써 동일한 문제를 다른 알고리즘으로 해결할 수 있게 하는 디자인 패턴이다.
즉, 전략을 쉽게 바꿀 수 있도록 해주는 디자인 패턴이다.
- 전략이란?
어떤 목적을 달성하기 위해 일을 수행하는 방식, 비즈니스 규칙, 문제를 해결하는 알고리즘 등
특히 게임 프로그래밍에서 게임 캐릭터가 자신이 처한 상황에 따라 공격이나 행동하는 방식을 바꾸고 싶을 때 스트래티지 패턴은 매우 유용하다.
- 전략 패턴 장점
-
시스템의 구조 및 Context Class를 변경하지 않고 요청에 맞는 로직을 추가 및 수정할 수 있다.
-
같은 인터페이스 양식을 가진 알고리즘을 별도로 캡슐화하여 코드의 가독성이 높아지며, 생산성이 높아진다.
-
요청에 맞는 로직을 실시간으로 변경할 수 있다.
- 전략 패턴 구조
-
Strategy
인터페이스나 추상 클래스로 외부에서 동일한 방식으로 알고리즘을 호출하는 방법을 명시한다. -
ConcreteStrategy
스트래티지 패턴에서 명시한 알고리즘을 실제로 구현한 클래스이다. -
Context
스트래티지 패턴을 이용하는 역할을 수행한다.
필요에 따라 동적으로 구체적인 전략을 바꿀 수 있도록 setter 메서드(‘집약 관계’)를 제공한다.
- 예제 코드
KickBehavior
public interface KickBehavior {
public void kick();
}
JumpBehavior
public interface JumpBehavior {
public void jump();
}
LightningKick : ConcreteStrategy
public class LightningKick implements KickBehavior{
@Override
public void kick() {
System.out.println("Lightning Kick");
}
}
TornadoKick : ConcreteStrategy
public class TornadoKick implements KickBehavior{
@Override
public void kick() {
System.out.println("Tornado Kick");
}
}
LongJump : ConcreteStrategy
public class LongJump implements JumpBehavior{
@Override
public void jump() {
System.out.println("Long Jump");
}
}
ShortJump : ConcreteStrategy
public class ShortJump implements JumpBehavior{
@Override
public void jump() {
System.out.println("Short Jump");
}
}
Fighter : Context
public abstract class Fighter {
KickBehavior kickBehavior;
JumpBehavior jumpBehavior;
public Fighter(KickBehavior kickBehavior, JumpBehavior jumpBehavior) {
this.kickBehavior = kickBehavior;
this.jumpBehavior = jumpBehavior;
}
public void punch() {
System.out.println("Default Punch");
}
public void kick() {
kickBehavior.kick();
}
public void jump() {
jumpBehavior.jump();
}
public void roll() {
System.out.println("Default Roll");
}
public void setKickBehavior(KickBehavior kickBehavior) {
this.kickBehavior = kickBehavior;
}
public void setJumpBeahvior(JumpBehavior jumpBehavior) {
this.jumpBehavior = jumpBehavior;
}
public abstract void display();
}
Kim
public class Kim extends Fighter{
public Kim(KickBehavior kickBehavior, JumpBehavior jumpBehavior) {
super(kickBehavior, jumpBehavior);
}
@Override
public void display() {
System.out.println("KIM");
}
}
Main Class
public class FighterMain {
public static void main(String[] args) {
JumpBehavior shortJump = new ShortJump();
JumpBehavior LongJump = new LongJump();
KickBehavior tornadoKick = new TornadoKick();
Fighter kim = new Kim(tornadoKick, shortJump);
kim.display();
kim.punch();
kim.kick();
kim.jump();
kim.setJumpBeahvior(LongJump);
kim.jump();
}
}
7. 템플릿 메서드 패턴 (Template method pattern)
- 템플릿 메서드 패턴이란?
상위 클래스에서 처리의 흐름을 제어하며, 하위클래스에서 처리의 내용을 구체화하는 디자인 패턴이다.
공통되는 사항은 상위 추상 클래스에서 구현하며, 각 객체마다 다른 부분은 하위 클래스에서 구현한다.
상속을 통한 확장 개발 방법으로 코드의 중복을 줄이고, 리팩토링(Refactoring)에 유리하여 가장 많이 사용되는 패턴 중 하나이다.
- 템플릿 메서드 패턴 구조
- Abstract Class : 추상 클래스로 templateMethod를 정의한다.
- Concrete Class : 부모 클래스에서 abstract로 정의된 templateMethod를 구현한다.
- 예제 코드
OrderProcessTemplate : Abstract Class
public abstract class OrderProcessTemplate {
public abstract void doSelect();
public abstract void doPayment();
public abstract void doDelivery();
public final void giftWrap() {
try {
System.out.println("Gift wrap successful");
} catch (Exception e) {
System.out.println("Gift wrap unsuccessful");
}
}
public final void processOrder(boolean isGift) {
doSelect();
doPayment();
if (isGift) giftWrap();
doDelivery();
}
}
StoreOrder : Concrete Class
public class StoreOrder extends OrderProcessTemplate {
@Override
public void doSelect() {
System.out.println("Do Select : Customer chooses the item from shelf.");
}
@Override
public void doPayment() {
System.out.println("Do Payment : Pays at counter through cash/POS");
}
@Override
public void doDelivery() {
System.out.println("Do Delivery : Item deliverd to in delivery counter.");
}
}
NetOrder : Concrete Class
public class NetOrder extends OrderProcessTemplate {
@Override
public void doSelect() {
System.out.println("Do Select : Item added to online shopping cart");
System.out.println("Do Select : Get gift wrap preference");
System.out.println("Do Select : Get delivery address.");
}
@Override
public void doPayment() {
System.out.println
("Do Payment : Online Payment through Netbanking, card or Paytm");
}
@Override
public void doDelivery() {
System.out.println
("Do Delivery : Ship the item through post to delivery address");
}
}
Main Class
public class OrderMain {
public static void main(String[] args) {
OrderProcessTemplate netOrder = new NetOrder();
netOrder.processOrder(true);
System.out.println();
OrderProcessTemplate storeOrder = new StoreOrder();
storeOrder.processOrder(true);
}
}
8. 방문자 패턴 (visitor Pattern)
- 방문자 패턴이란?
실제 로직을 가지고 있는 객체(Visitor)가 로직을 적용할 객체(Element)를 방문하면서 실행하는 패턴이다.
즉, 로직과 구조를 분리하는 패턴이라고 볼 수 있다.
로직과 구조가 분리되면 구조를 수정하지 않고도 새로운 동작을 기존 객체 구조에 추가할 수 있다.
비슷한 종류의 객체들을 가진 그룹에서 작업을 수행해야 할 때 주로 사용되는 패턴이다.
- 방문자 패턴 구조
-
Visitor
명령을 수행하기 위해 필요한 메소드를 정의하는 인터페이스이다. -
ConcreteVisitor
명령을 수행하는 메소드를 구현한다. -
Element
Visit를 사용할 수 있는지 확인하는 accept 메소드를 정의하는 인터페이스이다. -
ConcreteElement
Visitable에서 정의된 accept 메소드를 구현하며 Visitor객체는 이 객체를 통하여 명령이 전달된다.
- 예제 코드
ItemElement : Element
public interface ItemElement {
public int accept(ShoppingCartVisitor visitor);
}
ShoppingCartVisitor : Visitor
public interface ShoppingCartVisitor {
int visit(Book book);
int visit(Fruit fruit);
}
Book : ConcreteElement
public class Book implements ItemElement{
private int price;
private String isbnNumber;
public Book(int cost, String isbn) {
this.price = cost;
this.isbnNumber = isbn;
}
public int getPrice() {
return price;
}
public String getIsbnNumber() {
return isbnNumber;
}
@Override
public int accept(ShoppingCartVisitor visitor) {
return visitor.visit(this);
}
}
Fruit : ConcreteElement
public class Fruit implements ItemElement{
private int pricePerKg;
private int weight;
private String name;
public Fruit(int priceKg, int weight, String name) {
this.pricePerKg = priceKg;
this.weight = weight;
this.name = name;
}
public String getName() {
return name;
}
public int getPricePerKg() {
return pricePerKg;
}
public int getWeight() {
return weight;
}
@Override
public int accept(ShoppingCartVisitor visitor) {
return visitor.visit(this);
}
}
ShoppingCartVisitorImpl : ConcreteVisitor
public class ShoppingCartVisitorImpl implements ShoppingCartVisitor{
@Override
public int visit(Book book) {
int cost = 0;
if(book.getPrice() > 50) cost = book.getPrice()-5;
else cost = book.getPrice();
System.out.println("Book ISBN : " + book.getIsbnNumber() + " cost = " + cost);
return cost;
}
@Override
public int visit(Fruit fruit) {
int cost = fruit.getPricePerKg() * fruit.getWeight();
System.out.println(fruit.getName() + " cost = " + cost);
return cost;
}
}
Main Class
public class ShoppingCartMain {
public static void main(String[] args) {
ItemElement[] items = new ItemElement[]{new Book(20, "What is Justice?"), new Book(100, "DesignPattern"),
new Fruit(10, 2, "Banana"), new Fruit(5, 5, "Apple")};
int total = calculatePrice(items);
System.out.println("Total Cost = " + total);
}
private static int calculatePrice(ItemElement[] items) {
ShoppingCartVisitor visitor = new ShoppingCartVisitorImpl();
int sum = 0;
for (ItemElement item : items) {
sum = sum + item.accept(visitor);
}
return sum;
}
}
9. 중재자 패턴 (Mediator Pattern)
- 중재자 패턴이란?
객체들 간의 상호작용 행위를 정리하여 모은 중재자 객체를 따로 두어 관리하는 디자인 패턴이다.
모든 클래스간의 복잡한 로직(상호작용)을 캡슐화하여 하나의 클래스에 위임하여 처리하는 패턴이다.
즉, M:N의 관계에서 M:1의 관계로 복잡도를 떨어뜨려 유지 보수 및 재사용의 확장성에 유리한 패턴이다. 커뮤니케이션을 하고자 하는 객체가 있을 때 서로가 커뮤니케이션 하기 복잡한 경우 이를 해결해주고 서로 간 쉽게 해주며 커플링을 약화시켜주는 패턴이다.
객체들간 커뮤니케이션 정의가 되었지만, 복잡할 때(종합이 필요할 때)사용한다.
- 중재자 패턴이 사용되는 경우
- 객체들간의 관계가 매우 복잡하여 객체의 재사용에 부담이 갈 경우
- 중재자 패턴 장점
-
객체들 간 수정을 하지않고 관계를 수정할 수 있다.
-
객체들간의 관계의 복잡도, 의존성 및 결합도를 감소시킨다.
- 중재자 패턴 구조
-
Mediator
Colleague 객체간의 상호작용을 위한 인터페이스를 정의한다. -
ConcreteMediator
Mediator의 인터페이스를 구현하여 객체간의 상호작용을 조정한다. -
Colleague
다른 Colleague와의 상호작용을 위한 인터페이스를 정의한다. -
ConcreteColleague
Colleague의 인터페이스를 구현하며 Mediator를 통해 다른 Colleague와 상호작용한다.
- 예제 코드
Command : Mediator
public interface Command {
void land();
}
Flight : ConcreteMediator
public class Flight implements Command {
private IATCMediator atcMediator;
public Flight(IATCMediator atcMediator) {
this.atcMediator = atcMediator;
}
@Override
public void land() {
if (atcMediator.isLandingOK()) {
System.out.println("Successfylly Landed.");
atcMediator.setLandingStatus(true);
} else {
System.out.println("Waiting for Landing.");
}
}
public void getReady() {
System.out.println("Ready for landing");
}
}
Runway : ConcreteMediator
public class Runway implements Command{
private IATCMediator atcMediator;
public Runway(IATCMediator atcMediator) {
this.atcMediator = atcMediator;
atcMediator.setLandingStatus(true);
}
@Override
public void land() {
System.out.println("Lading permission granted.");
atcMediator.setLandingStatus(true);
}
}
IATCMediator : Colleague
public interface IATCMediator {
public void registerRunway(Runway runway);
public void registerFilght(Flight flight);
public boolean isLandingOK();
public void setLandingStatus(boolean status);
}
ATCMediator : ConcreteColleague
public class ATCMediator implements IATCMediator {
private Flight flight;
private Runway runway;
public boolean land;
@Override
public void registerRunway(Runway runway) {
this.runway = runway;
}
@Override
public void registerFilght(Flight flight) {
this.flight = flight;
}
@Override
public boolean isLandingOK() {
return land;
}
@Override
public void setLandingStatus(boolean status) {
land = status;
}
}
Main Class
public class IATCMediatorMain {
public static void main(String[] args) {
IATCMediator atcMediator = new ATCMediator();
Flight cptJack = new Flight(atcMediator);
Runway runnerWay = new Runway(atcMediator);
atcMediator.registerFilght(cptJack);
atcMediator.registerRunway(runnerWay);
cptJack.getReady();
runnerWay.land();
cptJack.land();
}
}
10. 상태 패턴 (State Pattern)
- 상태 패턴이란?
상태 디자인 패턴은 객체 내부의 상태에 따라 동작을 변경해야할 때 사용하는 디자인 패턴이다.
즉, 객체의 특정 상태를 클래스로 선언하고 클래스에서는 해당 상태에서 할 수 있는 행위들을 메서드로 정의한다.
그리고 이러한 각 상태 클래스들을 인터페이스로 캡슐화 하여 클라이언트에서 인터페이스를 호출한다.
- 상태 패턴 장점
-
하나의 객체에 대한 여러 동작을 구현해야할 때 상태 객체만 수정하므로 동작의 추가, 삭제 및 수정이 간단하다.
-
State 패턴을 사용하면 객체의 상태에 따른 조건문(if/else, switch)이 줄어들어 코드가 간결해지고 가독성이 올라간다.
- 상태 패턴 구조
-
Context
객체의 상태를 정의하는 데 사용되는 메소드를 정의하는 인터페이스이다. -
State
상태에 따른 동작을 정의하는 인터페이스이다. -
ConcreteState
State에서 정의된 메소드를 구현하는 클래스이다.
- 예제 코드
MobileAlertState : State
public interface MobileAlertState {
public void alert(AlertStateContext ctx);
}
AlertStateContext : Context
public class AlertStateContext {
private MobileAlertState currentState;
public AlertStateContext() {
currentState = new Vibration();
}
public void setState(MobileAlertState state) {
currentState = state;
}
public void alert() {
currentState.alert(this);
}
}
Vibration : ConcreteState
public class Vibration implements MobileAlertState {
@Override
public void alert(AlertStateContext ctx) {
System.out.println("Vibration");
}
}
Slient : ConcreteState
public class Slient implements MobileAlertState {
@Override
public void alert(AlertStateContext ctx) {
System.out.println("Silent");
}
}
Main Class
public class AlertMain {
public static void main(String[] args) {
AlertStateContext stateContext = new AlertStateContext();
stateContext.alert();
stateContext.setState(new Slient());
stateContext.alert();
}
}
11. 기념품 패턴 (Memento Pattern)
- 기념품 패턴이란?
기념품 패턴은 객체의 상태 정보를 가지는 클래스를 따로 생성하여 객체의 상태를 저장하거나 이전 상태로 복원할 수 있게 해주는 패턴이다. 기념품 패턴은 바둑, 오목, 체스 등의 보드게임 등에서 '무르기' 기능을 구현할 때 사용되기도 한다.
단, 이전 상태의 객체를 저장하기 위한 Originator가 클 경우 많은 메모리가 필요하다.
- 기념품 패턴 구조
-
Originator
객체의 상태를 저장한다.
Memento 객체를 생성하며 후에 Memento를 사용하여 실행 취소(undo)를 할 수 있다. -
Memento
Originator의 상태를 유지하는 객체이다.(POJO) -
Caretaker
마치 게임의 세이브포인트처럼 복수의 Memento의 상태를 유지해주는 객체이다.
Life : Originator / Memento
public class Life {
private String time;
public void setTime(String time) {
System.out.println("Setting Time : " + time);
this.time = time;
}
public Memento saveToMemento() {
System.out.println("Saving time to Memento");
return new Memento(time);
}
public void restoreFromMemento(Memento memento) {
time = memento.getSavedTime();
System.out.println("Time restored from Memento : " + time);
}
public static class Memento {
private final String time;
public Memento(String timeToSave) {
this.time = timeToSave;
}
public String getSavedTime() {
return time;
}
}
}
Main Class : Caretaker
public class LifeMain {
public static void main(String[] args) {
List<Life.Memento> savedTimes = new ArrayList<Life.Memento>();
Life life = new Life();
life.setTime("1000 B.C.");
savedTimes.add(life.saveToMemento());
life.setTime("1000 A.D.");
savedTimes.add(life.saveToMemento());
life.setTime("2000 A.D.");
savedTimes.add(life.saveToMemento());
life.setTime("4000 A.D.");
savedTimes.add(life.saveToMemento());
life.restoreFromMemento(savedTimes.get(0));
}
}
Author And Source
이 문제에 관하여(Design Pattern : 행동 패턴(Behavioral Patterns) 2), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@ha0kim/Design-Pattern-행동-패턴Behavioral-Patterns-2저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)