아무거나

스트레티지 패턴 본문

Java/Java

스트레티지 패턴

전봉근 2019. 8. 12. 10:35
반응형

[스트레티지 패턴]

스트레티지 패턴(Strategy Pattern)

어떤 객체를 만들 때 객체가 가지는 기능들이 다양하게 존재할 것 입니다. 이러한 기능들을 추상화 하여 언제든지 적용할 수 있게 만드는 것 입니다.

즉, 기능을 부품화 하는 것 입니다.

 

예를 들어 포니와 그랜저 자동차가 있습니다. 포니에 들어가는 기어 연결부분과 그랜저에 들어가는 연결부분이 동일하다고(추상화) 하면, 저급기어, 중급기어,

고급기어를 만들어 두고 상황에 따라서 적당한 기어를 적용할 수 있다. 즉 포니에는 저급기어를, 그랜저에는 고급기어를 적용하는것이다.

이렇게 기능을 부품화하여 구조를 만드는 것을 스트레티지라고 생각하면 된다.

 

아래 예제로 로봇을 프로그램으로 만들어 보는 것이다.

[시나리오]

1. 로봇 모양은 팔, 다리, 머리, 몸통으로 이루어져 있다.

2. 모든 로봇은 기본적으로 걷고, 달릴 수 있어야 한다.

3. Super로봇은 날수 있고, 미사일을 쏠 수 있으며, 레이저 검을 가지고 있다.

4. Standard 로봇은 날수는 없지만 미사일을 쏠 수 있다. 그리고 레이저 검은 없지만, 목검은 가지고 있다.

5. Low 로봇은 날수도 없고, 미사일을 쏠 수도 없습니다. 그리고 레이저검 또는 목검도 없다.

 

(1) MainClass 생성

 

(2) SuperRobot 생성 

    [SuperRobot.java]

public class SuperRobot {
    public SuperRobot() {
		// constructor
    }

    public void actionWalk() {
		System.out.println("걸을 수 있다.");
    }

    public void actionRun() {
		System.out.println("달릴 수 있다.");
    }

    public void actionFly() {
		System.out.println("날 수 있다.");
    }

    public void actionMisail() {
		System.out.println("미사일을 쏠 수 있다.");
    }

    public void actionKnife() {
		System.out.println("레이저검이 있다.");
    }

    public void shape() {
		System.out.println("SuperRobot 로봇 입니다. 외형은 팔, 다리, 몸통 머리가 있다.");
    }
}

 

만약 클라이언트가 원하는 위에 슈퍼로봇말고 다른 로봇을 만들어 달라고 하면 클래스를 새로 생성해주면 된다. 

예제를 위하여 위에 유형별 로봇클래스를 생성해준다.

 

(3) 로봇별로 공통적인 기능은 로봇이라는 슈퍼클래스를 만들어놓고 그것을 로봇별로 상속받게 구조를 설계한다.

 

(4) 로봇별로 클래스를 만든것들을 확인해보면 메소드명은 다 똑같은데 안에서 구현하는것만 다르다는것을 알 수 있고

    이럴경우엔 추상메서드로 추상화 시켜버릴 수 있다. (abstract)

    [Robot.java] 

public abstract class Robot {
    public void actionWalk() {
		System.out.println("걸을 수 있다.");
    }

    public void actionRun() {
		System.out.println("달릴 수 있다.");
    }

    public void shape() {
		System.out.println("SuperRobot 로봇 입니다. 외형은 팔, 다리, 몸통 머리가 있다.");
    }

    public abstract void actionFly();
    public abstract void actionMisail();
    public abstract void actionKnife();
}

 

    [SuperRobot.java]

public class SuperRobot extends Robot {
    public SuperRobot() {
		// constructor
    }

    @Override
    public void actionFly() {
		System.out.println("날 수 있다.");
    }

    @Override
    public void actionMisail() {
		System.out.println("미사일을 쏠 수 있다.");
    }

    @Override
    public void actionKnife() {
		System.out.println("레이저검이 있다.");
    }
}

 

(5) 인터페이스를 저장할 패키지를 생성 후 각각의 인터페이스를 생성하자

    [IFly.java]

public interface IFly {
    void fly();
}

 

....... (Misail, Knife 인터페이스도 생성..)

 

(6) 인터페이스를 implements하는 클래스를 생성하자.

    [FlyNo.java]

public class FlyNo implements IFly {
    @Override
    public void fly() {
		System.out.println("날 수 없습니다.");
    }
}

 

    [KnifeLazer.java]

public class KnifeLazer implements IKnife {
    @Override
    public void knife() {
		System.out.println("레이저 검이 있습니다.");
    }
}

 

    [KnifeNo.java]

public class KnifeNo implements IKnife {
    @Override
    public void knife() {
		System.out.println("검이 없습니다.");
    }
}

 

    등.. 각각의 기능별로 클래스를 생성하면 된다.

 

(7) 인터페이스 적용(로봇별로 적용하자.)

    [SuperRobot.java]

import com.javalec.robotex.inter.IFly;
import com.javalec.robotex.inter.IKnife;
import com.javalec.robotex.inter.IMisail;

public class SuperRobot extends Robot {
    // IKnife knife = new KnifeLazer(); 생성을 하지 않고
    // 아래와 같이 선언만 해놓고 setter를 이용하여 할당할 수 있다.
    // 처음에 객체를 만들때는 어떤 기능일지 모르니 일단은 선언만 해놓는다(날 수 있는지 없는지 그런거에 대한 명확성이 없으므로)
    IFly fly;
    IMisail misail;
    IKnife knife;

    public SuperRobot() {
		// constructor
    }

    @Override
    public void actionFly() {
		System.out.println("날 수 있다.");
    }

    @Override
    public void actionMisail() {
		System.out.println("미사일을 쏠 수 있다.");
    }

    @Override
    public void actionKnife() {
		System.out.println("레이저검이 있다.");
    }

    public void setFly(IFly fly) {
		this.fly = fly;
    }

    public void setMisail(IMisail misail) {
		this.misail = misail;
    }

    public void setKnife(IKnife knife) {
		this.knife = knife;
    }
}

 

** 이제 사용자들이 사용을 할 때 FlyYes인지 FlyNo인지 결정하면 그때그때 부품을 변경할 수 있다.

** 아래 내용의 소스는 공통적인것이므로 슈퍼클래스인 Robot쪽으로 가져간다.

[Robot.java]

import com.javalec.robotex.inter.IFly;
import com.javalec.robotex.inter.IKnife;
import com.javalec.robotex.inter.IMisail;

public abstract class Robot {
    // IKnife knife = new KnifeLazer(); 생성을 하지 않고
    // 아래와 같이 선언만 해놓고 setter를 이용하여 할당할 수 있다.
    // 처음에 객체를 만들때는 어떤 기능일지 모르니 일단은 선언만 해놓는다(날 수 있는지 없는지 그런거에 대한 명확성이 없으므로)
    IFly fly;
    IMisail misail;
    IKnife knife;

    public Robot() {}

    public void actionWalk() {
		System.out.println("걸을 수 있다.");
    }

    public void actionRun() {
		System.out.println("달릴 수 있다.");
    }

    public void shape() {
		System.out.println("SuperRobot 로봇 입니다. 외형은 팔, 다리, 몸통 머리가 있다.");
    }

    public abstract void actionFly();
    public abstract void actionMisail();
    public abstract void actionKnife();

    public void setMisail(IMisail misail) {
		this.misail = misail;
    }

    public void setKnife(IKnife knife) {
		this.knife = knife;
    }

    public void setFly(IFly fly) {
		this.fly = fly;
    }
}

 

(8) actionFly, actionMisail 등과 같이 얘네 메소드들은 이미 위의 과정에서 객체로 만들어 놨으므로

    로봇별 클래스마다 제거해주면 된다. 그렇게 되면 추상클래스인 Robot에서 에러가 나오는데

    원인은 상속받는 클래스에서 오버라이드를 안해줘서이다. 어차피 객체화 시켰으므로

    과감히 추상메서드를 지워주자. 그렇게 되면 각 로봇의 코드는 생성자밖에 없다.

 

(9) 실행을 하는 코드를 생성하자. 예를 들어 knife인데 레이저검이 있는지 목검이 있는지 검이 없는지 그것을 실행해주는 코드가 없다.

    상위(Robot)에서 그 실행코드를 호출해주는 메서드를 작성하자.(오버라이드한 부분을 호출)

    [Robot.java]

import com.javalec.robotex.inter.IFly;
import com.javalec.robotex.inter.IKnife;
import com.javalec.robotex.inter.IMisail;

public abstract class Robot {

    // IKnife knife = new KnifeLazer(); 생성을 하지 않고
    // 아래와 같이 선언만 해놓고 setter를 이용하여 할당할 수 있다.
    // 처음에 객체를 만들때는 어떤 기능일지 모르니 일단은 선언만 해놓는다(날 수 있는지 없는지 그런거에 대한 명확성이 없으므로)
    IFly fly;
    IMisail misail;
    IKnife knife;

    public Robot() {}

    public void actionWalk() {
		System.out.println("걸을 수 있다.");
    }

    public void actionRun() {
		System.out.println("달릴 수 있다.");
    }

    public void shape() {
		System.out.println("SuperRobot 로봇 입니다. 외형은 팔, 다리, 몸통 머리가 있다.");
    }

    public void setMisail(IMisail misail) {
		this.misail = misail;
    }

    public void setKnife(IKnife knife) {
		this.knife = knife;
    }

    public void setFly(IFly fly) {
		this.fly = fly;
    }

    public void actionFly() {
		this.fly.fly();
    }

    public void actionKnife() {
		this.knife.knife();
    }

    public void actionMisail() {
		this.misail.misail();
    }
}

 

(10) Shape를 보면 무조건 SuperRobot으로만 출력해준다 그러므로 추상클래스로 빼준다.

     public abstract void shape();  // Robot.java 추가

 

     // SuperRobot.java 에 추가.. 다른 클래스들도 로봇별로 추가해 주자.

     @Override

     public void shape() {

        System.out.println("SuperRobot 로봇 입니다. 외형은 팔, 다리, 몸통 머리가 있다.");

     }

 

(11) 결과

SuperRobot을 만들어 주세요.

SuperRobot 로봇 입니다. 외형은 팔, 다리, 몸통 머리가 있다.

걸을 수 있다.

달릴 수 있다.

날 수 있습니다.

미사일을 쏠 수 있습니다.

레이저 검이 있습니다.​ 

반응형

'Java > Java' 카테고리의 다른 글

Calendar api  (0) 2019.08.12
String의 이해  (0) 2019.08.12
싱글턴 패턴(Singleton Pattern)  (0) 2019.08.09
인터페이스  (0) 2019.08.08
추상클래스(abstract)  (0) 2019.08.08
Comments