[스프링 입문을 위한 자바 객체 지향의 원리와 이해] 06. 스프링이 사랑한 디자인 패턴

off_sujin·2022년 6월 26일
0

어댑터 패턴(Adapter Pattern)

변환기의 역할은 서로 다른 두 인터페이스 사이에 통신이 가능하게 하는 것이다.

어댑터 패턴은 합성, 즉 객체를 속성으로 만들어서 참조하는 디자인 패턴이다.

즉, 어댑터 패턴은 개방 폐쇄 원칙을 활용한 설계 패턴이다.

"호출당하는 쪽의 메서드를 호출하는 쪽의 코드에 대응하도록 중간에 변환기를 통해 호출하는 패턴"

프록시 패턴(Proxy Pattern)

프록시는 대리자, 대변인(다른 누군가를 대신해 그 역할을 수행하는 존재)이라는 뜻을 가진다.

  • 대리자는 실제 서비스와 같은 이름의 메서드를 구현하는데, 이를 위해 인터페이스를 사용한다.
  • 대리자는 실제 서비스에 대한 참조 변수를 갖는다.(합성)
  • 대리자는 실제 서비스의 같은 이름을 가진 메서드를 호출하고 그 값을 클라이언트에게 돌려준다.
  • 대리자는 실제 서비스의 메서드 호출 전후에 별도의 로직을 수행할 수도 있다.

프록시 패턴은 실제 서비스 메서드의 반환값에 가감하는 것을 목적으로 하지 않고 제어의 흐름을 변경하거나 다른 로직을 수행하기 위해 사용한다.

"제어 흐름을 조정하기 위한 목적으로 중간에 대리자를 두는 패턴"

데코레이터 패턴(Decorator Pattern)

데코레이터 패턴은 클라이언트가 받는 반환값에 장식을 더한다는 점만 빼면 프록시 패턴과 동일하다.

  • 장식자는 실제 서비스와 같은 이름의 메서드를 구현한다. 이때 인터페이스를 사용한다.
  • 장식자는 실제 서비스에 대한 참조 변수를 갖는다(합성).
  • 장식자는 실제 서비스의 같은 이름을 가진 메서드를 호출하고, 그 반환값에 장식을 더해 클라이언트에게 돌려준다.
  • 장식자는 실제 서비스의 메서드 호출 전후에 별도의 로직을 수행할 수 있다.

    "메서드 호출의 반환값에 변화를 주기 위해 중간에 장식자를 두는 패턴"

싱글턴 패턴(Singleton Pattern)

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

싱글턴 패턴의 특징

  • private 생성자를 갖는다.
  • 단일 객체 참조 변수를 정적 속성으로 갖는다.
  • 단일 객체 참조 변수가 참조하는 단일 객체를 반환하는 getInstance() 정적 메서드를 갖는다.
  • 단일 객체는 쓰기 가능한 속성을 갖지 않는 것이 정석이다.
// Singleton의 예제
public class Singleton {
  static Singleton singletonObject;// 정적 참조 변수
  
  private Singleton() {};// private 생성자
  
  //객체 반환 정적 메서드
  public static Singleton getInstance() {
    if (singletonObject == null) {
      singletonObject = new Singleton();
    }
    
    return singletonObject;
  }
}

"클래스의 인스턴스, 즉 객체를 하나만 만들어 사용하는 패턴"

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

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

템플릿 메서드 패턴의 구성

템플릿 메서드

  • 공통 로직을 수행, 로직 중에 하위 클래스에서 오버라이딩한 추상 메서드/훅 메서드를 호출

템플릿 메서드에서 호출하는 추상 메서드

  • 하위 클래스가 반드시 오버라이딩해야 한다.

템플릿 메서드에서 호출하는 훅(Hook, 갈고리) 메서드

  • 하위 클래스가 선택적으로 오버라이딩한다.

"상위 클래스의 템플릿(견본) 메서드에서 하위 클래스가 오버라이딩한 메서드를 호출하는 패턴"

팩터리 메서드 패턴(Factory Method Pattern)

오버라이드된 메서드가 객체를 반환하는 패턴

팩터리 메서드는 객체를 생성 반환하는 메서드를 말한다.
하위 클래스에서 팩터리 메서드를 오버라이딩해서 객체를 반환하게 하는 것이다.

-> 객체를 생성하는 인터페이스는 미리 정의하되, 어떤 클래스의 인스턴스를 생성할 지에 대
한 결정은 서브클래스에서 이루어지도록 하는 패턴이다.

기존 코드(인스턴스를 만드는 과정)를 수정하지 않고 새로운 인스턴스를 다른 방법으로 생성하도록 확장할 수 있다!!

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

public abstract class Animal {
	// 추상 팩터리 메서드
	abstract AnimalToy getToy();
}

//추상 클래스를 나타내는 AnimalToy.java
// 팩터리 메서드가 생성할 객체의 상위 클래스
public abstract class AnimalToy {
	abstract void identify();
}
//Dog.java
package factoryMethodPattern;

public class Dog extends Animal {
	// 추상 팩터리 메서드 오버라이딩
	@Override
	AnimalToy getToy() {
		return new DogToy();
	}
}

//DogToy.java
//팩터리 메서드가 생성할 객체
public class DogToy extends AnimalToy {
	public void identify() {
		System.out.println("나는 테니스공! 강아지의 친구!");
	}
}
//Cat.java
package factoryMethodPattern;

public class Cat extends Animal {
	// 추상 팩터리 메서드 오버라이딩
	@Override
	AnimalToy getToy() {
		return new CatToy();
	}
}

//CatToy.java
//팩터리 메서드가 생성할 객체
public class CatToy extends AnimalToy {
	@Override
	public void identify() {
		System.out.println("나는 캣타워! 고양이의 친구!");
	}
}
//Driver.java
package factoryMethodPattern;

public class Driver {
	public static void main(String[] args) {
		// 팩터리 메서드를 보유한 객체들 생성
		Animal bolt = new Dog();
		Animal kitty = new Cat();

		// 팩터리 메서드가 반환하는 객체들
		AnimalToy boltBall = bolt.getToy();
		AnimalToy kittyTower = kitty.getToy();

		// 팩터리 메서드가 반환한 객체들을 사용
		boltBall.identify();
		kittyTower.identify();
	}
}

전략 패턴(Strategy Pattern)

클라이언트가 전략을 생성해 전략을 실행할 컨텍스트에 주입하는 패턴

<전략 패턴을 구성하는 3가지 요소>

  • 전략 메서드를 가진 전략 객체
  • 전략 객체를 사용하는 컨텍스트(전략 객체의 사용자/소비자)
  • 전략 객체를 생성해 컨텍스트에 주입하는 클라이언트(제3자, 전략 객체의 공급자)

클라이언트는 다양한 전략 중 하나를 선택해 생성한 후 컨텍스트에 주입한다.

ex) 군인

무기 - 전략
군인 - 컨텍스트
보급 장교 - 클라이언트

//전략 인터페이스를 나타내는 Strategy.java
package strategyPattern;

public interface Strategy {
	public abstract void runStrategy();
}
//전략 인터페이스를 구현하는 StrategyGun.java
package strategyPattern;

public class StrategyGun implements Strategy {
	@Override
	public void runStrategy() {
		System.out.println("탕, 타탕, 타다당");
	}
}

//전략 인터페이스를 구현하는 StrategySword.java
public class StrategySword implements Strategy {
	@Override
	public void runStrategy() {
		System.out.println("챙.. 채쟁챙 챙챙");
	}
}

//전략 인터페이스를 구현하는 StrategyBow.java
public class StrategyBow implements Strategy {
	@Override
	public void runStrategy() {
		System.out.println("슝.. 쐐액.. 쉑, 최종 병기");
	}
}
//전략을 사용하는 컨텍스트 Soldier.java
package strategyPattern;

public class Soldier {
	void runContext(Strategy strategy) {
		System.out.println("전투 시작");
		strategy.runStrategy();
		System.out.println("전투 종료");
	}
}
//전략 패턴의 클라이언트 Client.java
package strategyPattern;

public class Client {
	public static void main(String[] args) {
		Strategy strategy = null;
		Soldier rambo = new Soldier();

		//총을 람보에게 전달해서 전투를 수행하게 한다.
		strategy = new StrategyGun();
		rambo.runContext(strategy);

		System.out.println();

		// 검을 람보에게 전달해서 전투를 수행하게 한다.
		strategy = new StrategySword();
		rambo.runContext(strategy);

		System.out.println();

		// 활을 람보에게 전달해서 전투를 수행하게 한다.
		strategy = new StrategyBow();
		rambo.runContext(strategy);
	}
}

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

전략 패턴의 변형으로, 스프링의 3대 프로그래밍 모델 중 하나인 DI(의존성 주입)에서 사용하는 특별한 형태의 전략 패턴이다.

전략을 익명 내부 클래스로 정의해서 사용한다는 것을 제외하면 전략 특징과 동일하다.

//전략 인터페이스 Strategy.java
package templateCallbackPattern;

public interface Strategy {
	public abstract void runStrategy();
}
//전략을 사용하는 컨텍스트 Soldier.java
package templateCallbackPattern;

public class Soldier {
	void runContext(Strategy strategy) {
		System.out.println("전투 시작");
		strategy.runStrategy();
		System.out.println("전투 종료");
	}
}
//익명 내부 전략을 사용하는 클라이언트 Client.java
package templateCallbackPattern;

public class Client {
	public static void main(String[] args) {
		Soldier rambo = new Soldier();

		rambo.runContext(new Strategy() {
			@Override
			public void runStrategy() {
				System.out.println("총! 총초종총 총! 총!");
			}
		});

		System.out.println();

		rambo.runContext(new Strategy() {
			@Override
			public void runStrategy() {
				System.out.println("칼! 카가갈 칼! 칼!");
			}
		});

		System.out.println();

		rambo.runContext(new Strategy() {
			@Override
			public void runStrategy() {
				System.out.println("도끼! 독독..도도독 독끼!");
			}
		});
	}
}

스프링이 사랑한 다른 패턴들

프론트 컨트롤러 패턴

각 클라이언트들은 Front Controller에 요청을 보내고,

Front Controller은 각 요청에 맞는 컨트롤러를 찾아서 호출시킨다.

공통 코드에 대해서는 Front Controller에서 처리하고, 서로 다른 코드들만 각 Controller에서 처리할 수 있도록 한다.

MVC 패턴

도메인(비즈니스 로직) 영역과 UI 영역을 분리시켜 서로 영향을 주지 않고 유지보수가 가능하다.

Model

  • 어플리케이션의 정보, 데이터
  • 비즈니스 로직을 처리한 후 모델의 변경사항을 컨트롤러와 뷰에 전달한다.

View

  • 사용자에게 보여지는 부분, 즉 유저 인터페이스(User interface)
  • 받은 데이터를 화면에 표시해주는 역할

Controller

  • 모델(Model)과 뷰(View) 사이를 이어주는 브릿지(Bridge) 역할
  • 사용자가 어플리케이션을 조작하여 발생하는 변경 이벤트들을 처리하는 역할
profile
학습 중..

0개의 댓글