Spring/additional

[Spring] 스프링이 사랑한 디자인 패턴2

sujin7837 2021. 2. 21. 01:04
반응형

[개요]

 

스프링이 사랑한 디자인 패턴1

1. Adapter Pattern(어댑터 패턴)

2. Proxy Pattern(프록시 패턴)

3. Decorator Pattern(데코레이터 패턴)

 

스프링이 사랑한 디자인 패턴2

1. Singleton Pattern(싱글턴 패턴)

2. Template Method Pattern(템플릿 메소드 패턴)

3. Factory Method Pattern(팩토리 메소드 패턴)

 

스프링이 사랑한 디자인 패턴3

1. Strategy Pattern(전략 패턴)

2. Template Callback Pattern(템플릿 콜백 패턴_견본/회신 패턴)

3. MVC 패턴

 

Singleton Pattern(싱글턴 패턴)

-싱글턴 패턴은 인스턴스를 하나만 만들어 사용하기 위한 패턴으로, 만든 인스턴스를 계속해서 재사용합니다.

-싱글턴 패턴을 적용할 경우 의미상 두 개의 객체가 존재할 수 없으므로, 객체 생성을 위한 new에 제약을 걸어야 하고, 만들어진 단일 객체를 반환할 수 있는 메소드가 필요합니다.

-싱글턴 패턴은 클래스의 인스턴스, 즉 객체를 하나만 만들어 사용하는 패턴입니다.

 

싱글턴 패턴에 필요한 3가지 요소

  • new를 실행할 수 없도록 생성자에 private 접근 제어자를 지정합니다.
  • 유일한 단일 객체를 반환할 수 있는 정적 메소드가 필요합니다.
  • 유일한 단일 객체를 참조할 정적 참조 변수가 필요합니다.
//Singleton.java

public class Singleton {
	static Singleton singletonObject;	//정적 참조 변수
    
    private Singleton() { };	//private 생성자
    
    //객체 반환 정적 메소드
    public static Singleton getInstance() {
    	if(singletonObject==null) {
        	singletonObject=new Singleton();
        }
        
        return singletonObject;
    }
}

-정적 참조 변수: 단일 객체를 저장하기 위한 변수

-private 생성자: new를 통해 객체를 생성할 수 없도록 생성자에 private을 지정

-getInstance() 정적 메소드: 단일 객체를 반환하기 위한 정적 메소드로, 정적 참조 변수에 객체가 할당되어 있지 않은 경우에만 new를 통해 객체를 만들고 정적 참조 변수를 할당합니다. 그리고 정적 참조 변수에 할당되어 있는 유일한 객체의 참조를 반환합니다.

 

//Client.java

public class Client {
	public static void main(String[] args) {
    	//private 생성자이므로 new를 통해 인스턴스를 생성할 수 없다.
        //Singleton s=new Singleton();
        
        Singleton s1=Singleton.getInstance();
        Singleton s2=Singleton.getInstance();
        Singleton s1=Singleton.getInstance();
        
        System.out.println(s1);
        System.out.println(s1);
        System.out.println(s1);
        
        s1=null;
        s2=null;
        s3=null;
    }
}

위 코드의 실행 결과

->SingletonPattern.Singleton@263c8db9

    SingletonPattern.Singleton@263c8db9

    SingletonPattern.Singleton@263c8db9

 

toString() 메소드를 별도로 오버라이딩하지 않았으므로 객체의 고유 값인 hashcode를 반환하게 되며, 3개의 참조 변수인 s1, s2, s3가 동일한 값을 출력하는 것을 볼 수 있습니다.

 

위 그림에서 4개의 참조 변수(singletonObject, s1, s2, s3)가 하나의 단일 객체를 참조하는 것을 볼 수 있습니다. 단일 객체가 속성을 갖게 되면 하나의 참조 변수가 변경한 단일 객체의 속성이 다른 참조 변수에 영향을 미치기 때문에 속성을 갖지 않는 것이 정석입니다. 다만 읽기 전용 속성을 갖는 것은 문제가 되지 않으며, 단일 객체가 다른 단일 객체에 대한 참조를 속성으로 가진 것 또한 문제가 되지 않습니다.

 

싱글턴 패턴의 중요한 특징

  • private 생성자를 가집니다.
  • 단일 객체 참조 변수를 정적 속성으로 가집니다.
  • 단일 객체 참조 변수가 참조하는 단일 객체를 반환하는 getInstance() 정적 메소드를 가집니다.
  • 단일 객체는 쓰기 가능한 속성을 갖지 않는 것이 정석입니다.

 

Template Method Pattern(템플릿 메소드 패턴)

-템플릿 메소드 패턴은 상위 클래스에 공통 로직을 수행하는 템플릿 메소드와 하위 클래스에 오버라이딩을 강제하는 추상 메소드 또는 선택적으로 오버라이딩할 수 있는 훅(Hook) 메소드를 두는 패턴입니다.

-템플릿 메소드 패턴은 상위 클래스의 견본 메소드에서 하위 클래스가 오버라이딩한 메소드를 호출하는 패턴입니다.

-템플릿 메소드 패턴은 의존 역전 원칙(DIP)을 활용하고 있습니다.

 

//Dog.java

public class Dog {
	public void playWithOwner() {
    	System.out.println("귀염둥이 이리온...");
        System.out.println("멍! 멍!");
        System.out.println("꼬리 살랑 살랑~");
        System.out.println("잘했어");
    }
}
//Cat.java

public class Cat {
	public void playWithOwner() {
    	System.out.println("귀염둥이 이리온...");
        System.out.println("야옹~ 야옹~");
        System.out.println("꼬리 살랑 살랑~");
        System.out.println("잘했어");
    }
}

위 두 코드에서 두 번째 출력문을 제외하고는 모두 동일한 것을 볼 수 있습니다. 위 코드를 개선해보겠습니다.

 

//상위 클래스를 포함하는 Animal.java

public abstract class Animal {
	//템플릿 메소드
    public void playWithOwner() {
    	System.out.println("귀염둥이 이리온...");
        play();
        runSomething();
        System.out.println("잘했어");
    }
    
    //추상 메소드
    abstract void play();
    
    //Hook(갈고리) 메소드
    void runSomething() {
    	System.out.println("꼬리 살랑 살랑~");
    }
}

상위 클래스인 Animal에는 템플릿(견본)을 제공하는 playWithOwner() 메소드와 하위 클래스에게 구현을 강제하는 play() 추상 메소드, 하위 클래스가 선택적으로 오버라이딩할 수 있는 runSomething() 메소드가 있습니다.

//하위 클래스를 포함하는 Dog.java

public class Dog extends Animal {
	@Override
    //추상 메소드 오버라이딩
    void play() {
    	System.out.println("멍! 멍!");
    }
    
    @Override
    //Hook(갈고리) 메소드 오버라이딩
    void runSomething() {
    	System.out.println("멍! 멍!~ 꼬리 살랑 살랑~");
    }
}
//하위 클래스를 포함하는 Cat.java

public class Cat extends Animal {
	@Override
    //추상 메소드 오버라이딩
    void play() {
    	System.out.println("야옹~ 야옹~");
    }
    
    @Override
    //Hook(갈고리) 메소드 오버라이딩
    void runSomething() {
    	System.out.println("야옹~ 야옹~ 꼬리 살랑 살랑~");
    }
}

하위 클래스인 Dog과 Cat은 상위 클래스인 Animal에서 구현을 강제하고 있는 play() 추상 메소드를 반드시 구현해야 하며, runSomething() 메소드는 선택적으로 오버라이딩할 수 있습니다.

 

 

템플릿 메소드 패턴의 특징

템플릿 메소드 패턴의 구성 요소 상위 클래스 Animal 하위 클래스 Dog/Cat
템플릿 메소드
(공통 로직을 수행, 로직 중에 하위 클래스에서 오버라이딩한 추상 메소드/훅 메소드를 호출)
playWithOwner()  
템플릿 메소드에서 호출하는 추상 메소드
(하위 클래스가 반드시 오버라이딩해야 함)
play() 오버라이딩 필수
템플릿 메소드에서 호출하는 훅(Hook, 갈고리) 메소드
(하위 클래스가 선택적으로 오버라이딩 함)
runSomething() 오버라이딩 선택

 

Factory Method Pattern(팩토리 메소드 패턴)

-팩토리 메소드는 객체를 생성 반환하는 메소드를 말합니다.

-팩토리 메소드 패턴은 하위 클래스에서 팩토리 메소드를 오버라이딩해서 객체를 반환하게 하는 것을 의미합니다.

-팩토리 메소드 패턴은 오버라이드된 메소드가 객체를 반환하는 패턴입니다.

-팩토리 메소드 패턴은 의존 역전 원칙을 활용합니다.

//추상 클래스를 나타내는 Animal.java

public abstract class Animal {
	//추상 팩토리 메소드
    abstract AnimalToy getToy();
}
//추상 클래스를 나타내는 AnimalToy.java

//팩토리 메소드가 생성할 객체의 상위 클래스
public abstract class AnimalToy {
	abstract void identity();
}

반응형