💡스프링 프레임워크의 공식적인 정의
"자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크"
→ "OOP 프레임워크" (책 필자의 생각)
이 책을 지금까지 읽어보았을 때 나도 필자의 생각에 동의한다.
package adapterPattern;
public class ServiceA {
void runServiceA() {
System.out.println("ServiceA");
}
}
package adapterPattern;
public class ServiceB {
void runServiceB() {
System.out.println("ServiceB");
}
}
package adapterPattern;
public class AdapterServicA {
ServiceA sa1 = new ServiceA();
void runService() {
sa1.runServiceA();
}
}
package adapterPattern;
public class AdapterServicB {
ServiceB sb1 = new ServiceB();
void runService() {
sb1.runServiceB();
}
}
//어댑터 패턴이 적용되지 않은 코드
package adapterPattern;
public class ClientWithNoAdapter {
public static void main(String[] args) {
ServiceA sa1 = new ServiceA();
ServiceB sb1 = new ServiceB();
sa1.runServiceA();
sb1.runServiceB();
}
}
//어댑터 패턴이 적용된 코드
package adapterPattern;
public class ClientWithAdapter {
public static void main(String[] args) {
AdapterServicA asa1 = new AdapterServicA();
AdapterServicB asb1 = new AdapterServicB();
asa1.runService();
asb1.runService();
}
}
클라이언트(ClientWithAdapter)가 변환기를 통해 runService()라는 동일한 메서드명으로 두 객체의 메서드를 호출하는 것을 볼 수 있다.
//IService.java
package proxyPattern;
public interface IService {
String runSomething();
}
//IService 인터페이스를 구현한 Service.java
package proxyPattern;
public class Service implements IService {
public String runSomething() {
return "서비스 짱!!!";
}
}
//IService 인터페이스를 구현한 Proxy.java
package proxyPattern;
public class Proxy implements IService {
IService service1;
public String runSomething() {
System.out.println("호출에 대한 흐름 제어가 주목적, 반환 결과를 그대로 전달");
service1 = new Service();
return service1.runSomething();
}
}
//프록시를 사용하는 ClientWithProxy.java
package proxyPattern;
public class ClientWithProxy {
public static void main(String[] args) {
//프록시를 이용한 호출
IService proxy = new Proxy();
System.out.prinln(proxy.runSomething());
}
}
//IService.java
package decoratorPattern;
public interface IService {
public abstract String runSomething();
}
//IService 인터페이스를 구현한 Service.java
package decoratorPattern;
public class Service implements IService {
public String runSomething() {
return "서비스 짱!!!";
}
}
//IService 인터페이스를 구현한 Decorator.java
package decoratorPattern;
public class Decoreator implements IService {
IService service;
public String runSomething() {
System.out.println("호출에 대한 장식 주목적, 클라이언트에게 반환 결과에 장식을 더하여 전달");
service = new Service();
return "정말" + service.runSomething();
}
}
//데코레이터를 사용하는 ClientWithDecorator.java
package decoratorPattern;
public class ClientWithDecolator {
public static void main(String[] args) {
IService decoreator = new Decoreator();
System.out.println(decoreator.runSomething());
}
}
//Singleton.java
package singletonPattern;
public class Singleton {
static Singleton singletonObject; // 정적 참조 변수
private Singleton() {
}; // private 생성자
// 객체 반환 정적 메서드
public static Singleton getInstance() {
if (singletonObject == null) { //정적 참조 변수에 객체가 할당돼 있지 않은 경우에만 new를 통해 객체를 만들고 정적 참조 변수에 할당
singletonObject = new Singleton();
}
return singletonObject;
}
}
//Client.java
package singletonPattern;
public class Client {
public static void main(String[] args) {
// private 생성자임으로 new 할 수 없다.
// Singleton s = new Singleton();
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
Singleton s3 = Singleton.getInstance();
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
s1 = null;
s2 = null;
s3 = null;
}
}
4개의 참조 변수가 하나의 단일 객체를 참조 → 싱글턴 패턴의 힘
단일 객체인 경우 결국 공유 객체로 사용되기 때문에 속성을 갖지 않게 하는 것이 정석이다. 단일 객체가 속성을 갖게 되면 하나의 참조 변수가 변경한 단일 객체의 속성이 다른 참조 변수에 영향을 미치기 때문이다. 읽기 전용 속성을 갖는 것은 문제가 되지 않는다. 단일 객체가 다른 단일 객체에 대한 참조를 속성으로 가진 것 또한 문제가 되지 않는다.
public class Dog {
public void playWithOwner() {
System.out.println("귀염둥이 이리온...");
**System.out.println("멍! 멍!");**
System.out.println("꼬리 살랑 살랑~");
System.out.println("잘했어");
}
}
public class Cat {
public void playWithOwner() {
System.out.println("귀염둥이 이리온...");
**System.out.println("야옹~ 야옹~");**
System.out.println("꼬리 살랑 살랑~");
System.out.println("잘했어");
}
}
진한 글씨채의 코드를 제외한 코드가 모두 비슷하다는 것을 관찰할 수 있다.
//상위 클래스를 포함하는 Animal.java
package templateMethodPattern;
public abstract class Animal {
// 템플릿 메서드
public void playWithOwner() {
System.out.println("귀염둥이 이리온...");
play();
runSomething();
System.out.println("잘했어");
}
// 추상 메서드
abstract void play();
// Hook(갈고리) 메서드
void runSomething() {
System.out.println("꼬리 살랑 살랑~");
}
}
//하위 클래스를 포함하는 Dog.java
package templateMethodPattern;
public class Dog extends Animal {
@Override
// 추상 메서드 오버라이딩
void play() {
System.out.println("멍! 멍!");
}
@Override
// Hook(갈고리) 메서드 오버라이딩
void runSomething() {
System.out.println("멍! 멍!~ 꼬리 살랑 살랑~");
}
}
//하위 클래스를 포함하는 Cat.java
package templateMethodPattern;
public class Cat extends Animal {
@Override
// 추상 메서드 오버라이딩
void play() {
System.out.println("야옹~ 야옹~");
}
@Override
// Hook(갈고리) 메서드 오버라이딩
void runSomething() {
System.out.println("야옹~ 야옹~ 꼬리 살랑 살랑~");
}
}
//Driver.java
package templateMethodPattern;
public class Driver {
public static void main(String[] args) {
Animal bolt = new Dog();
Animal kitty = new Cat();
bolt.playWithOwner();
System.out.println();
System.out.println();
kitty.playWithOwner();
}
}
//추상 클래스를 나타내는 Animal.java
package factoryMethodPattern;
public abstract class Animal {
// 추상 팩터리 메서드
abstract AnimalToy getToy();
}
//추상 클래스를 나타내는 AnimalToy.java
package factoryMethodPattern;
// 팩터리 메서드가 생성할 객체의 상위 클래스
public abstract class AnimalToy {
abstract void identify();
}
//Dog.java
package factoryMethodPattern;
public class Dog extends Animal {
// 추상 팩터리 메서드 오버라이딩
@Override
AnimalToy getToy() {
return new DogToy();
}
}
//DogToy.java
package factoryMethodPattern;
//팩터리 메서드가 생성할 객체
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
package factoryMethodPattern;
//팩터리 메서드가 생성할 객체
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.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
package strategyPattern;
public class StrategySword implements Strategy {
@Override
public void runStrategy() {
System.out.println("챙.. 채쟁챙 챙챙");
}
}
//전략 인터페이스를 구현하는 StrategyBow.java
package strategyPattern;
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);
}
}
//전략 인터페이스 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();
/*
* Strategy strategy = new StrategyGun();
* rambo.runContext(strategy);
*/
/*
* Strategy strategy = new IStrategy() {
*
* @Override public void doStrategy() {
* System.out.println("총! 총초종총 총! 총!"); } };
*
* rambo.runContext(strategy);
*/
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("도끼! 독독..도도독 독끼!");
}
});
}
}
Refactoring...
//Strategy.java
package templateCallbackPatternRefactoring;
public interface Strategy {
public abstract void runStrategy();
}
//Soldier.java
package templateCallbackPatternRefactoring;
public class Soldier {
void runContext(String weaponSound) {
System.out.println("전투 시작");
executeWeapon(weaponSound).runStrategy();
System.out.println("전투 종료");
}
private Strategy executeWeapon(final String weaponSound) {
return new Strategy() {
@Override
public void runStrategy() {
System.out.println(weaponSound);
}
};
}
}
//Client.java
package templateCallbackPatternRefactoring;
public class Client {
public static void main(String[] args) {
Soldier rambo = new Soldier();
rambo.runContext("총! 총초종총 총! 총!");
System.out.println();
rambo.runContext("칼! 카가갈 칼! 칼!");
System.out.println();
rambo.runContext("도끼! 독독..도도독 독끼!");
}
}