모든지 기록하자!

[Java] 디자인패턴 ( singleton, factory) 예제 본문

Java

[Java] 디자인패턴 ( singleton, factory) 예제

홍크 2021. 5. 24. 20:10
728x90

디자인 패턴 중에 핵심적인 singleton과 factory를 예를 통해 알아보자

 

 

객체 지향 프로그램에서 인스턴스를 단 하나만 생성하는 디자인 패턴을 싱글톤(singleton) 패턴이라고 한다.

sington패턴을 이용해서 클래스 간에 변수 값을 공유하게 한다.

public class SingletonClass {
	
	private static SingletonClass si = null; // 객체를 생성하지 않고 호출하기 위해 static으로 선언
	public int s_num; // SingletonClass에 멤버변수
	public String s_name; // SingletonClass에 멤버변수
	
	public SingletonClass() { //디폴트 생성자
		
	}
	public static SingletonClass getInstance() {
		if(si == null) {
			si = new SingletonClass(); // 인스턴스 si가 null이면 SingletonClass생성
		}
		return si; // si를 반환
	}
}

싱글톤 패턴에서는 생성자를 반드시 명시적으로 만들고 그 접근 제어자를 private로 지정해야 한다.

명시적으로 생성자를 구현해놓지 않으면 여러 개의 인스턴스가 생성될 수 있기 때문이다.

그렇기 때문에 직접 Default생성자를 구현하고 외부에서 생성자를 호출하지 못하게 priavate로 선언한다.

객체를 생성 후에 method를 호출해야 하기 때문에 객체를 생성하지 않고 호출하기 위해 static으로 선언한다.

 

public class MyClass {

	private int number; // 멤버변수
	
	public MyClass() { // MyClass가 생성되면 멤버변수 number에 256값을 대입
		number = 256;
	}

	public int getNumber() {
		return number;
	}
	
	public void method() { // SingletonClass에 s_num에 멤버변수 number값 256을 대입
		SingletonClass si = SingletonClass.getInstance();
		si.s_num = number;
	}

}
public class YouClass {

	private int num; // SingletonClass에서 s_num값을 전달 받을 멤버 변수
	private String name = "성춘향"; // HeClass에 전달해줄 name 멤버 변수
	
	public void setNum(int num) {
		this.num = num;
	}
	public int getNum() {
		return num;
	}
	
	public void func() { // 메소드 호출시 SingletonClass를 생성해 s_num값을 멤버변수 num에 대입
		SingletonClass si = SingletonClass.getInstance();
		num = si.s_num;
	}
	public void method() {
		SingletonClass si = SingletonClass.getInstance(); //SingletonClass를 생성해서
		si.s_name = getName();                      // name값을 s_name변수에 대입
	}

	public String getName() {
		return name;
	}
}
public class HeClass {

	private String name;
	
	public void func() {
		SingletonClass si = SingletonClass.getInstance(); // SingletonClass를 생성해서
		name = si.s_name;                               // s_name값을 멤버변수 name에 대입
	}

	public String getName() {
		return name;
	}

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

 

public class MainClass {

	public static void main(String[] args) {

		MyClass mycls =  new MyClass(); // MyClass 생성
		YouClass youcls = new YouClass(); // YouClass 생성
		
		mycls.method(); // MyClass의 number값 256을 s_num에 대입하는 메서드 호출
		youcls.func(); // SingletonClass의 s_num값을 YouClass의 멤버변수 name에 대입하는 메서드 호출
		
		System.out.println(youcls.getNum()); // YouClass에 num값을 가져온다.
		
		HeClass hecls = new HeClass(); // HeClass 생성
		
		youcls.method(); // YouClass의 name멤버변수 값을 s_name에 대입하는 메서드 호출
		hecls.func(); // SingletonClass의 s_name값을 HeClass의 멤버변수 name에 대입하는 메서드 호출
		
		System.out.println(hecls.getName()); // HeClass의 name값을 가져온다.
	}

}

출력 결과

youcls.getNum : 256
hecls.getName : 성춘향

 

 

factory예제

클래스 구조는 위 사진과 같다.

public interface Weapon { // 인터페이스 생성

	public void drawWeapon();
}
public class Gun implements Weapon { // Weapon 인터페이스를 상속받는다.

	@Override
	public void drawWeapon() { // 인터페이스 상속받을시 반드시 부모의 메서드를 재정의해야한다.
		System.out.println("weapon:기관총");
	}
}
public class Sword implements Weapon {

	@Override
	public void drawWeapon() {
		System.out.println("sword:장검");
	}
}
public interface Bomb { // 인터페이스 생성

	public void drawBomb(); 
}
public class Dynamite implements Bomb { // Bomb 인터페이스를 상속받는다.

	@Override
	public void drawBomb() {
		System.out.println("Bomb: Dynamite"); // Bomb인터페이스에 있는 메서드 재정의
	}
}
public class C4 implements Bomb {

	@Override
	public void drawBomb() {
		System.out.println("Bomb: C4");
	}
}
public interface AbstractItem { // 인터페이스 생성
 
	public Weapon createWeapon(); // 인터페이스에 선언한 메서드는 
	public Bomb createBomb();     // 컴파일 과정에서 추상메서드로 변환된다.
}
public class AtypeClass implements AbstractItem{ // AbstractItem인터페이스 상속받는다.

	@Override
	public Weapon createWeapon() { //추상메서드를 재정의한다.
		return new Gun(); // Weapon 클래스를 상속받은 Gun클래스 생성
	}

	@Override
	public Bomb createBomb() {
		return new C4(); // Bomb 클래스를 상속받은 C4클래스 생성
	}
}
public class BtypeClass implements AbstractItem{ // AbstractItem 인터페이스를 상속받는다.

	@Override
	public Weapon createWeapon() {
		return new Sword(); /// Weapon 클래스를 상속받은 Sword클래스 생성
	}

	@Override
	public Bomb createBomb() { 
		return new Dynamite(); // Bomb 클래스를 상속받은 Dynamite클래스 생성
	}
}
public class Person {
	
	public Weapon mWeapon;
	public Bomb mBomb;
	
	public void create(AbstractItem ai) {  // create메서드 호출시에
		mWeapon = ai.createWeapon();   // 매개변수로 AbstractItem 인터페이스를 받는다.
		mBomb = ai.createBomb();
	}
}
public class MainClass {

	public static void main(String[] args) {

		Person char1 = new Person(); // Person클래스 생성
		char1.create(new AtypeClass()); // create메서드 호출 AtypeClass 클래스를 매개변수로 넣는다.
		
		char1.mWeapon.drawWeapon();  // AtypeClass클래스에  drawWeapon 메서드 호출 
		char1.mBomb.drawBomb(); // AtypeClass클래스에  drawBomb 메서드 호출 
		
		System.out.println("===========");
		
		Person char2 = new Person(); // Person클래스 생성
		char2.create(new BtypeClass());  // create메서드 호출 BtypeClass 클래스를 매개변수로 넣는다.
		char2.mWeapon.drawWeapon();  // BtypeClass클래스에  drawWeapon 메서드 호출 
		char2.mBomb.drawBomb();  // BtypeClass클래스에  drawBomb 메서드 호출 
	}
}

출력결과

 

 

728x90
Comments