[Design Pattern] 싱글톤(Singleton) 패턴



프로그램 내에서 1개의 인스턴스만 생성 하기 위해서 필요한 것이 Singleton 패턴 입니다. 프로그램의 전역에서 사용될 설정 정보 값은 Singleton 패턴을 이용해 한개만 생성해 정보를 공유 하는데도 필요합니다. 사용자가 주의해서 1개만 생성하는것이 아닌 프로그램적으로 보증하는 방법을 제공해 줍니다.


싱글톤 패턴



싱글톤 패턴을 이용해 클래스를 만들어 보고 인스턴스가 1개 이상 생성되는지 확인해 보자.


[Singleton 구현]

싱글톤 클래스의 생성자는 private로 되어 있다. 이것은 싱글톤 클래스 외부에서 생성자를 호출을 금지하기 위해서다. 해당 패턴을 이용하면 프로그래머가 실수를 해도 인스턴스가 1개만 생성되도록 보증을 해주고 있다.


public class Singleton {

private static Singleton singleton = new Singleton();

private Singleton() {

System.out.println("인스턴스를 생성했습니다.");

}

public static Singleton getInstance() {

return singleton;

}

}



[Main 구현]


public class Main {

public static void main(String[] args) {

Singleton sing1 = Singleton.getInstance();

Singleton sing2 = Singleton.getInstance();

if ( sing1 == sing2 ) {

System.out.println("같은 인스턴스 입니다.");

} else {

System.out.println("다른 인스턴스 입니다.");

}

}

}



[실행 결과]


인스턴스를 생성했습니다.

같은 인스턴스 입니다.




실행 결과와 같이 sing1, sing2에서 2번 객체를 빼왔는데 인스턴스는 단 한번만 생성 된 것을 확인 할 수 있다.




반응형

'프로그램 > Design Pattern' 카테고리의 다른 글

[디자인패턴] Factory Method 패턴  (0) 2018.06.03
[디자인패턴] Template Method 패턴  (0) 2018.06.02
[디자인패턴] Adapter 패턴  (0) 2018.06.01
[디자인패턴] Iterator  (0) 2018.05.22

[Design Pattern] Factory Method 패턴



팩토리 패턴을 이해하기 위해서는 우선 템플릿 패턴을 알아야한다. 왜냐하면 템플릿 패턴에 인스턴스 생성하는 부분까지 추상화 시켰기 때문이다.

팩토리 패턴은 처리 골격을 만들고 상속 받은 클래스가 구체적인 처리를 구현해 놓습니다. 또한 인스턴스를 생성하는 부분까지 맡겼기 때문에 해당 클래스를 호출하는 부분에서는 따로 인스턴스를 만드는 과정을 없앴습니다.


팩토리 메소드 패턴



다목적 공장이 있습니다. 이 공장을 가지고 있으면 철강, 차, 베터리 등등 모든 것을 만들 수 있다. 이 공장을 이용해 차를 만드는 과정을 프로그램화 해보겠다. 다목적 공장에 해당하는 Framework 패키지 안에 Factory와 Product가 있다. 이 공장들을 이용해 차를 만드는 것은 Car 패키지에 Factory를 상속 받은 CarFactory가 Product를 상속받은 Car를 만드는 과정을 알아보겠다.


[클래스 다이어그램]




[framework 패키지에 Product 구현]

다목적 공장에서 생산되는 상품 규격을 정의해 놓은 추상화 클래스 이다.

해당 규격에만 맞게 구현 할 수 있으면 Factory에서 어떠한 제품을 만들어 낼 수 있다.

package framework;


public abstract class Product {

public abstract void use();

}



[framework 패키지에 Factory 구현 ]

Factory 추상화 클래스에서는 Product를 생성한다. 이 클래스를 상속 받은 클래스는 해당 규격에 맞게 구현만 하면 어떠한 공장도 만들어 낼 수 있다.


package framework;


public abstract class Factory {

public final Product create(String owner) {

Product p = createProduct(owner);

registerProduct(p);

return p;

}

protected abstract Product createProduct(String owner);

protected abstract void registerProduct(Product product);

}



[car 패키지에 Car 클래스 구현]

Product를 상속 받아 실제로 차에 대한 기능을 구현 한다.


package car;

import framework.*;


public class Car extends Product {

private String owner;

Car(String owner) {

this.owner = owner;

System.out.println(owner + "의 차를 만듭니다.");

}

@Override

public void use() {

System.out.println(owner + "의 차를 이용합니다.");

}

public String getOwner() {

return owner;

}

}



[car 패키지에 CarFactory 클래스 구현]

Factory를 상속받은 CarFactory 클래스는 Car 클래스 인스턴스를 생성 한다. 더블어 ArrayList 클래스를 이용한 생성한 Car 주인에 대한 관리도 가능하다.


package car;

import framework.*;

import java.util.*;


public class CarFactory extends Factory{


private List owners = new ArrayList();

@Override

protected Product createProduct(String owner) {

return new Car(owner);

}


@Override

protected void registerProduct(Product product) {

owners.add(((Car)product).getOwner());

}

public List getOwners() {

return owners;

}


}



[Main 구현]

만들어 놓은 차 공장을 이용해 차를 생산해 보자.


import car.*;

import framework.*;


public class Main {


public static void main(String[] args) {

Factory factory = new CarFactory();

Car car1 = (Car) factory.create("김순희");

Car car2 = (Car) factory.create("박철수");

car1.use();

car2.use();

for( int i = 0 ; i < ((CarFactory)factory).getOwners().size() ; i++ ) {

System.out.println(((CarFactory)factory).getOwners().get(i));

}

}

}



[실행 결과]


김순희의 차를 만듭니다.

박철수의 차를 만듭니다.

김순희의 차를 이용합니다.

박철수의 차를 이용합니다.

김순희

박철수





반응형

[Design Pattern] Template Method 패턴



가정에서 요리할 때 필요한 모양틀이 있다. 별모양으로 된 이 틀은 밀가루 반죽을 넣으면 별 모양으로 된 쿠키가 된다. 또한 계란물을 넣으면 별모양 후라이가 되기도 한다.  프로그램을 할 때도 제공된 틀 클래스를 상속 받으면 상속 받은 클래스는 어떠한 것을 구현해도 호출 하는 쪽에서는 수정에 대한 영향도가 없이 다양한 결과를 만들어 낼 수 있다. 이것을 Template Method 패턴이라고 한다.


템플릿 메소드 패턴



가정에서 요리할 때 필요한 틀을 직접 프로그램 해보겠다.

아래 클래스 다이어그램을 보면 AbstractCookShape고정된 요리틀 추상 클래스가 있다. 이것을 상속 받은 CookieShape, EggShape은 틀의 모양을 갖은 쿠키와 계란후라이를 만들어 내는 역할을 한다.


[클래스 다이어그램]



[AbstractCookShape 구현]

재료를 넣고, 요리를 시작, 끝내는 3가지 함수가 있다. 

이 틀에만 맞춰서 구현하면 많은 요리기능을 갖은 클래스를 만들어 낼 수 있다.


public abstract class AbstractCookShape {

public abstract void pourMaterial(String material);

public abstract void startCook();

public abstract void endCook();

}



[CookieShape 구현]

AbstractCookShape을 상속 받아서 쿠키를 요리하는 클래스를 만든다.


public class CookieShape extends AbstractCookShape {

String material = "";

@Override

public void pourMaterial(String material) {

this.material = material;

}


@Override

public void startCook() {

System.out.println("별모양 "+material+"쿠키를 요리 합니다.");

}


@Override

public void endCook() {

System.out.println("별모양 "+material+"쿠키가 완료되었습니다.");

}

}



[EggShape 구현]

AbstractCookShape을 상속 받아서 계란후라이를 요리하는 클래스를 만든다.


public class EggShape extends AbstractCookShape {


String material = "";

@Override

public void pourMaterial(String material) {

this.material = material;

}


@Override

public void startCook() {

System.out.println("별모양 "+material+"후라이를 요리 합니다.");

}


@Override

public void endCook() {

System.out.println("별모양 "+material+"후라이가 완료되었습니다.");

}


}



[Main 구현]

만들어놓은 요리틀을 사용해보자.


public class Main {


public static void main(String[] args) {

AbstractCookShape eggShape = new EggShape();

AbstractCookShape cookieShape = new CookieShape();

eggShape.pourMaterial("계란");

eggShape.startCook();

eggShape.endCook();

cookieShape.pourMaterial("밀가루반죽");

cookieShape.startCook();

cookieShape.endCook();

}

}





반응형

[Design Pattern] Adapter 패턴



한국에서 쓰는 가전 기기를 110V를 쓰는 나라에 가져가면 쓸 수가 없다. 왜냐면 우리나라는 220V로 규격화 되어 있기 때문이다. 110V를 쓰는 나라에서 우리나라 가전기기를 사용하려면 뭐가 필요 할까? 바로 아답터다. 220V 가전기기를 110V에서 사용하기 위해 꼭 필요하다. 프로그램에서도 마찮가지 이다. 이미 구현 되어 있는 Util Class가 존재 한다. 내가 만든 프로그램에서 해당 클래스를 사용하는데 알맞는 인터페이스가 존재 하지 않을 때가 있다. 이때 아덥터 패턴을 사용해 이미 구현된 Class를 사용해 보자.


상속을 사용한 Adapter 패턴



는 내비게이션을 가지고 있다. 이것을 새 차에 장착하고 싶은데 붙일 방법이 없다. 그래서 거치대를 사서 붙였다.

이 상황을 프로그램 해보겠다.


[가전 제품과 예제 비교]

 예제 프로그램

가전 제품 비유

 Car

한국에서 쓰는 가전 제품 

 거치대(Adapter)

아뎁터 (Adapter)

 내비게이션

V110


[클래스 다이어그램]



[전체 예제]

[차에서 내비를 실행]

public class Main {


public static void main(String[] args) {

Car carHasNavi = new Adapter();

carHasNavi.powerOnNavi();

carHasNavi.powerOffNavi();


}

}


===========================================================================================

[차 에서 내비게이션을 동작 하고 싶다.]


public interface Car {

void powerOnNavi();

void powerOffNavi();

}


===========================================================================================

[이미 존재 하는 내비게이션]

public class Navigation {

public void onStart() {

System.out.println("내비게이션 시작");

}

public void onDestory() {

System.out.println("내비게이션 종료");

}

}


===========================================================================================

[거치대는 네비게이션과 차를 상속 받아 결국에 차에서 내비를 실행 할 수 있게 된다.]

public class Adapter extends Navigation implements Car {


@Override

public void powerOnNavi() {

onStart();

}


@Override

public void powerOffNavi() {

onDestory();

}

}



위임을 사용한 Adapter 패턴



앞에서 보여줬던 예제와 비슷하지만 이전에는 상속을 통한 거치대를 구현 했다면 이번엔 위임을 통해 아뎁터 패턴을 알아보겠다.


[클래스 다이어그램]



[파일 쓰는 예제]

[차에서 내비를 실행]

public class Main {


public static void main(String[] args) {

Car carHasNavi = new Adapter();

carHasNavi.powerOnNavi();

carHasNavi.powerOffNavi();


}

}


===========================================================================================

[차 에서 내비게이션을 동작 하고 싶다.]


public abstract class Car {

public abstract void powerOnNavi();

public abstract void powerOffNavi();

}


===========================================================================================

[이미 존재 하는 내비게이션]

public class Navigation {

public void onStart() {

System.out.println("내비게이션 시작");

}

public void onDestory() {

System.out.println("내비게이션 종료");

}

}


===========================================================================================

[거치대는 차를 상속 받아 내부적으로 내비를 생성해 실행하고 있다.]

public class Adapter extends Car {


private Navigation navi = new Navigation();


@Override

public void powerOnNavi() {

navi.onStart();

}


@Override

public void powerOffNavi() {

navi.onDestory();

}

}



반응형

+ Recent posts