오직 하나의 인스턴스만 가지는 패턴으로 이 객체를 싱글턴이라고 이야기 합니다.
public class Singleton{
private static Singleton singleton = new Singleton(); // 정적 필드
private Singleton(){} // 생성자
static Singleton getInstance(){ // 정적메소드
return singleton;
}
}
객체의 생성 부분을 떼어내 추상화한 패턴이자 상송관계에 있는 두 클래스에서 상위 클래스가 중요 뼈대를 결정한 후 하위클래스에서 객체 생성에 관한 구체적인 내용을 결정하는 패턴입니다.
개별적으로 이름(name)을 반환하는 메소드를 작성했습니다.
public abstract class Fruit {
public abstract String getName();
}
public class Apple extends Fruit {
@Override
public String getName() {
return "Apple";
}
}
public class Banana extends Robot {
@Override
public String getName() {
return "Banana";
}
}
팩토리 메소드 패턴의 꽃은 역시 팩토리 클래스입니다. 차례대로 봅시다. 첫번째 보이는 코드는 기본 팩토리 클래스입니다.
public abstract class FruitFactory {
abstract Fruit createFruit(String name);
}
아래 클래스는 기본 팩토리 클래스를 상속 받아 실제 로직을 구현한 팩토리입니다.
public class SuperFruitFactory extends FruitFactory {
@Override
Fruit createFruit(String name) {
switch( name ){
case "Apple": return new Apple();
case "Banana": return new Banana();
}
return null;
}
}
아래 클래스는 SuperFruitFactory 클래스와 비슷하지만 내부 구현이 조금 다릅니다. 과일 클래스의 이름을 String 인자로 받아서 직접 인스턴스를 만들어 냅니다.
public class ModifiedSuperFruitFactory extends FruitFactory {
@Override
Robot createFruit(String name) {
try {
Class<?> cls = Class.forName(name);
Object obj = cls.newInstance();
return (Fruit)obj;
} catch (Exception e) {
return null;
}
}
}
준비가 다 되었다면 메인 프로그램을 작성해서 돌려봅시다.
public class FactoryMain {
public static void main(String[] args) {
FruitFactory rf = new SuperFruitFactory();
Fruit r1 = rf.createFruit("Apple");
Fruit r2 = rf.createFruit("Banana");
System.out.println(r.getName()); // Apple
System.out.println(r2.getName()); // Banana
FruitFactory ff = new ModifiedSuperFruitFactory();
Fruit r3 = mrf.createFruit("pattern.factory.Apple");
Fruit r4 = mrf.createFruit("pattern.factory.Banana");
System.out.println(r3.getName()); // Apple
System.out.println(r4.getName()); // Banana
}
}
정책 패턴이라고도 하며, 객체들이 할 수 있는 행위 각각에 대해 전략 클래스를 생성하고, 유사한 행위들을 캡슐화하는 인터페이스를 정의하여, 객체의 행위를 동적으로 바꾸고싶은 경우 직접 행위를 수정하지 않고 전략을 바꿔주기만 함으로써 행위를 유연하게 확장하는 방법입니다.
객체가 할 수 있는 행위들을 각각의 전략으로 만들어 놓고, 동적으로 행위의 수정이 필요한 경우 전략을 바꾸는 것만으로도 행위의 수정이 가능하기 때문에 사용합니다.
전략 - 추상화된 알고리즘을 설정합니다.
interface Sports {
void play();
}
class Soccer implements Sports {
@Override
public void play() {
System.out.println("축구를 합니다");
}
}
class Tennis implements Sports {
@Override
public void play() {
System.out.println("테니스를 합니다");
}
}
class Baseball implements Sports {
@Override
public void play() {
System.out.println("야구를 합니다");
}
}
Context에서 전략을 등록하고 실행합니다.
class PlaytheSports {
Sports sports;
void setSports(Sports sports) {
this.sports = sports;
}
void play() {
sports.play();
}
}
Client에서 전략 제공/설정해서 보여줍니다.
class User {
public static void main(String[] args) {
// 플레이어가 스포츠를 하도록 전략 설정
PlaytheSports sports = new PlaytheSports();
// 플레이어가 축구를 하도록 전략 변경
sports.setSports(new Soccer());
sports.play(); // "축구를 합니다"
// 플레이어가 테니스를 하도록 전략 변경
sports.setSports(new Tennis());
sports.play(); // "테니스를 합니다"
// 플레이어가 야구를 하도록 전략 변경
sports.setSports(new Baseball());
sports.play(); // "야구를 합니다"
}
}