SMALL

Strategy Pattern

객체들이 할 수 있는 행위 각각에 대해 전략 클래스를 생성하고, 유사한 행위들을 캡슐화하는 인터페이스를 정의하여, 객체의 행위를 동적으로 바꾸고 싶은 경우 직접 행위를 수정하지 않고 전략을 바꿔주기만 함으로써 행위를 유연하게 확장하는 방법을 말합니다.

 

간단히 말해서 

객체가 할 수 있는 행위들 각각을 전략으로 만들어 놓고, 동적으로 행위의 수정이 필요한 경우 전략을 바꾸는 것만으로 행위의 수정이 가능하도록 만든 패턴입니다.

 

 

객체지향 원칙

  • 바뀌는 부분은 캡슐화한다
  • 상속보다는 구성을 활용한다
  • 구현이 아닌 인터페이스에 맞춰서 프로그래밍한다

전략 패턴에서는 위의 원칙들을 포함하는 구조가 가능하다.

 

public abstract class Duck {
	
	FlyBehavior flyBehavior;
	QuackBehavior quackBehavior;
	
	public Duck() {
		
	}
	
	public void performFly() {
		flyBehavior.fly();
	}
	
	public void performQuack() {
		quackBehavior.quack();
	}
	
	public abstract void display();
	
	public void swim() {
		System.out.println("s w i m ~ ~ ");
	}
	
	public void setFlyBehavior(FlyBehavior fb) {
		flyBehavior = fb;
	}
	
	public void setQuackBehavior(QuackBehavior qb) {
		quackBehavior = qb;
	}
	
}

Duck에서는 FlyBehavior, QuackBehavior에 해당하는 전략을 가지고 있다.

 

public interface FlyBehavior {
	public void fly();
}

public interface QuackBehavior {
	public void quack();
}

 

그리고 마지막으로, Duck과 전략들의 구현체들을 보자

public class FlyNoWay implements FlyBehavior {
	@Override
	public void fly() {
		System.out.println(" I cannot fly ~ ");
	}
}

public class FlyWithWings implements FlyBehavior {
	@Override
	public void fly() {
		System.out.println(" fly in the moon ~ ");
	}
}

public class Quack implements QuackBehavior {
	@Override
	public void quack() {
		System.out.println("Quack ~~ Quack ~");
	}
}

public class Squeak implements QuackBehavior{
	@Override
	public void quack() {
		System.out.println("Squeak ~~ squeak ~ ");
	}
}

 

public class MallardDuck extends Duck {

	public MallardDuck() {
		quackBehavior = new Quack();
		flyBehavior = new FlyWithWings();
	}
	
	@Override
	public void display() {
		System.out.println("I'm MallarDuck~~ ~");
	}

}
LIST
SMALL

퍼사드 패턴은 프로그래밍 언어에서 관심사를 분리하는 패턴이다.

퍼사드의 어원은 프랑스어로 건물의 정면이라는 뜻을 갖고 있다.

건물의 외관, 겉모습을 말하며 사전적으로는 '표면, 허울'로도 해석된다.

 

퍼사드는 요즘과 같이 협업과 대형 시스템을 개발하고 배포하는 데 자주 응용되는 패턴이다.

퍼사드는 시스템 결합과 사용이 용이하도록 관심사를 분리한다.

 

출처 : https://jobc.tistory.com/22

퍼사드 패턴은 강력한 결합 구조를 해결하기 위해 코드의 의존성을 줄이고 느슨한 결합으로 구조를 변경한다.

퍼사드 패턴은 메인 시스템과 서브 시스템 중간에 위치하는데, 새로운 인터페이스 계층을 추가하여 시스템 간 의존성을 해결한다.

 

퍼사드는 GoF에서 설명하는 구조 패턴 중 하나며 퍼사드 패턴은 싱글턴 추상 팩토리라고 불리기도 한다. 

 

퍼사드는 복잡한 구조의 서브 시스템을 간단하게 호출할 수 있도록 하는 인터페이스 모음이다.

먼저, 퍼사드를 사용하지 않는 경우에 Client 코드를 보자.

public class Package1 {

    public void process() {
        System.out.println("Package 1 Process  ");
    }
}

public class Package2 {

    public void process() {
        System.out.println("Package process _");
    }
}

public class Package3 {

    public void process() {
        System.out.println("Package 3 - process");
    }
}

위의 내용은 서브시스템을 간략하게 예제를 위해 만든 것 들이다.

 

그럼 직접적으로 호출하는 코드는 아래와 같다.

    public static void main(String[] args) {
        Package1 p1 = new Package1();
        Package2 p2 = new Package2();
        Package3 p3 = new Package3();

        p1.process();
        p2.process();
        p3.process();

    }

이러한 식으로 사용자 코드에 서브 시스템의 클래스를 직접적으로 가져다 사용하게 되어서 결합도가 높아진다.

 

그러면 퍼사드 패턴을 사용하는 경우를 보자.

public class Facade {

    private Package1 p1;
    private Package2 p2;
    private Package3 p3;

    Facade() {
        p1 = new Package1();
        p2 = new Package2();
        p3 = new Package3();
    }

    public void processFacade() {
        p1.process();
        p2.process();
        p3.process();
    }
}
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.processFacade();

    }

각각의 패키지 객체를 직접 실행하는 것이 아니라 퍼사드 패턴의 메서드를 통해 한번에 실행한다.

 

퍼사드 패턴의 효과

  • 서브 시스템 보호
    • 클라이언트가 서브 시스템의 구성 요소를 직접 호출하지 않으므로 잘못된 사용을 방지할 수 있다
  • 확장성
  • 결합도 감소
    • 직접적으로 서브 시스템의 객체에 접근하지 않고 인터페이스와 유사한 역할을 하는 퍼사드를 이용하여 서브 시스템에 접근
  • 계층화
    • 서브 시스템이 계층화된 구조를 갖더라도 퍼사드는 계층 단계별로 접근하여 행위를 호출할 수 있다
  • 이식성
  • 공개 인터페이스
    • 퍼사드는 공개되는 기능만 인터페이스로 제공하는데, 이 경우 일시적으로 특정 기능을 감추는 효과를 얻을 수 있다

 

LIST
SMALL

장식자 패턴은 객체에 동적 기능을 추가하기 위해 구조를 개선하는 패턴이다.

다양한 확장을 위해 객체를 조합한다.

 

장식자 패턴은 기존 객체를 확장하기 위해 무언가를 추가 장식합니다.

장식자는 기본 베이스의 객체를 시작점으로 장식을 추가해 객체를 확장합니다.

장식자 패턴은 동적으로 객체를 결합하기 위해서 객체지향의 구성을 통해 확장한다.

 

장식자 패턴은 4개의 구성 요소로 이루어져 있습니다.

  • Component : 인터페이스를 정의
  • ConcreteComponent : 인터페이스에 정의 실제를 구현
  • Decorator : 컴포넌트를 참조하여 인터페이스를 일치화
  • ConcreteDecorator : 확장 및 추가되는 기능을 작성

 

Component - 공통 기능을 정의 

public interface Component {
    public String product();

    public int price();
}

 

ConcreteComponent

public class Product1 implements Component {

    @Override
    public String product() {

        return "one pice";
    }

    @Override
    public int price() {
        return 20000;
    }

}

 

Decorator 

장식자 패턴을 적용하기 위해 컴포넌트와 동일한 인터페이스를 유지해야 한다

public abstract class Decorate implements Component {
    abstract public String product();

    abstract public int price();
}

장식자 추상 클래스를 선언할 때 컴포넌트 인터페이스를 같이 적용

장식자는 객체를 확장할 때 구성을 사용한다.

인터페이스를 적용하는 이유는 단지 객체의 통일화된 사용을 위해서이다.

장식자는 실제 장식을 구현하기 위한 껍데기일 뿐이다.

 

ConcreteDecorator

public class CpuI7 extends Decorate {

    public Component base;

    CpuI7(Component concrete) {
        this.base = concrete;
    }

    @Override
    public String product() {
        return base.product() + ", i7";
    }

    @Override
    public int price() {
        return base.price() + 475000;
    }

}
public class Ssd256 extends Decorate {

    public Component base;

    Ssd256(Component concrete) {
        this.base = concrete;
    }

    @Override
    public String product() {
        return base.product() + ", ssd256";
    }

    @Override
    public int price() {
        return base.price() + 11000;
    }

}

 

실행 예시

    public static void main(String[] args) {
        Component p1 = new Product1(); // ConcreteComponent

        Component i7 = new CpuI7(p1); // ConcreteDecorator

        Component ssd256 = new Ssd256(i7); // ConcreteDecorator

        System.out.println("product : " + ssd256.product());
        System.out.println("price : " + ssd256.price());
    }
    
    //
    product : one pice, i7, ssd256
    price : 506000
LIST
SMALL

복합체 패턴은 객체 간의 계층적 구조화를 통해 객체를 확장하는 패턴이다.

복합체는 재귀적으로 결합된 계층화된 트리 구조의 객체이다.

 

복합 객체는 객체가 또 다른 객체를 포함하는 것을 말한다.

 

 

복합체 패턴은 크게 4개의 구성 요소로 이루어진다.

  • Component
  • Composite
  • Leaf
  • Client

복합체는 일반 객체, 복합 객체 구분 없이 재귀적 결합이 가능하다.

모두 동일한 객체로 처리하여 트리 구조를 쉽게 활용한다.

 

복합체의 구성 요소인 Composite, leaf는 엄밀히 다른 객체이다.

하지만 복합체는 2개의 객체를 모두 관리하기 위해 동일한 Component 인터페이스를 적용하여, 인터페이스에는 두 객체의 공통된 기능이 모두 포함된다.

복합체 패턴은 Component 인터페이스를 이용하여 Composite 객체와 Leaf 객체를 서로 구별하지 않고 동일한 동작으로 처리한다. 이를 투명성이라고 한다.

투명성은 복합체 패턴의 특징이다. 

 

다만, Component 인터페이스는 투명성을 보장하기 위해서 단일 책임 원칙을 위반한다.

( 두 가지 이상의 기능을 탑재하고 있음)

 

Component

public abstract class Component {
    
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


}

 

Leaf

계층적 트리 구조의 제일 마지막 객체 

public class Leaf extends Component {

    Leaf(String name) {
        this.setName(name);
    }

    private int price;

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

 

Composite

public class Composite extends Component {

    Composite(String name) {
        this.setName(name);
    }

    public List<Component> children = new ArrayList<>();

    public void addNode(Component component) {
        this.children.add(component);
    }

    public void removeNode(Component component) {
        this.children.remove(component);
    }

    public boolean isNode() {
        if (this.children.size() > 0) {
            return true;
        } else {
            return false;
        }
    }
}

 

Client

    public static void main(String[] args) {
        Composite root = new Composite("root");

        Composite home = new Composite("home");
        Composite users = new Composite("users");
        Composite temp = new Composite("temp");

        Component img1 = new Leaf("img1");
        Component img2 = new Leaf("img2");
        // Component img3 = new Leaf("img3");
        // Component img4 = new Leaf("img4");

        root.addNode(home);
        root.addNode(users);
        users.addNode(temp);
        temp.addNode(img1);
        temp.addNode(img2);

        Main mm = new Main();
        mm.tree(root, "");

    }
    public void tree(Composite composite, String depth) {

        List<Component> list = composite.children;

        for (Component com : list) {

            if (com instanceof Composite) {
                System.out.println("Folder:" + depth + com.getName());
                Composite temp = (Composite) com;
                if (temp.isNode()) {
                    tree(temp, depth + "  ");
                } else {
                    System.out.println(depth + "No Children");
                }

            } else if (com instanceof Leaf) {
                System.out.println("Leaf:" + depth + com.getName());
            } else {
                System.out.println("??");
            }
        }
    }

 

 

LIST

+ Recent posts