...

[Java] μŠ€ν”„λ§μ„ μ™œ μ‚¬μš©ν• κΉŒ?(2) - OCP와 DIP ν•΄κ²° By 순수 μžλ°”

KoB 2022. 2. 1. 11:25

 

μ§€λ‚œ ν¬μŠ€νŒ…μ—μ„œλŠ” OCP와 DIPκ°€ μœ„λ°° λ˜λŠ” κ²½μš°μ— λŒ€ν•΄μ„œ μ•Œμ•„λ³΄μ•˜μŠ΅λ‹ˆλ‹€. μ΄λ²ˆμ—λŠ” μŠ€ν”„λ§μ΄ μ•„λ‹Œ 순수 μžλ°”λ‘œ ν•΄κ²°ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

잠깐 μ§€λ‚œ κΈ€μ˜ 클래슀 λ‹€μ΄μ–΄κ·Έλž¨μ„ μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

public class DriverImpl implements Driver{

    Car car = new K3();
    Engine engine = new Electronic();

    @Override
    public void findOwnCarDetail() {
        car.findCarName();
        car.findCarBrand();
        engine.WayToMove();
    }
}

DriverImpl 역할에 κ΅¬ν˜„μ²΄κ°€ 직접 new ν‚€μ›Œλ“œλ‘œ μ„ μ–Έ λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. 이럴 경우 얼핏보면 OCP와 DIPλ₯Ό 잘 지킨 것 κ°™μ§€λ§Œ 사싀 μ•„λ‹ˆλΌκ³  μ§€λ‚œ ν¬μŠ€νŒ…μ—μ„œ λ§μ”€λ“œλ ΈμŠ΅λ‹ˆλ‹€.

 

μ΄λ²ˆμ—λ„ κ°“μ˜ν•œλ‹˜μ˜ 말을 λΉŒλ¦¬κ² μŠ΅λ‹ˆλ‹€. 

"λ‘œλ―Έμ˜€μ™€ 쀄리엣 곡연을 ν•˜λ©΄ 둜미였 역할을 λˆ„κ°€ ν• μ§€ 쀄리엣 역할을 λˆ„κ°€ ν• μ§€λŠ” λ°°μš°λ“€μ΄ μ •ν•˜λŠ”κ²Œ μ•„λ‹ˆλ‹€. 이전 μ½”λ“œλŠ” 마치 둜미였 μ—­ν• (μΈν„°νŽ˜μ΄μŠ€)을 ν•˜λŠ” λ ˆμ˜€λ‚˜λ₯΄λ„ λ””μΉ΄ν”„λ¦¬μ˜€(κ΅¬ν˜„μ²΄, 배우)κ°€ 쀄리엣 μ—­ν• (μΈν„°νŽ˜μ΄μŠ€)을 ν•˜λŠ” μ—¬μž 주인곡(κ΅¬ν˜„μ²΄, 배우)을 직접 μ΄ˆλΉ™ν•˜λŠ” 것과 κ°™λ‹€. λ””μΉ΄ν”„λ¦¬μ˜€λŠ” 곡연도 ν•΄μ•Όν•˜κ³  λ™μ‹œμ— μ—¬μž 주인곡도 곡연에 직접 μ΄ˆλΉ™ν•΄μ•Ό ν•˜λŠ” λ‹€μ–‘ν•œ μ±…μž„μ„ κ°€μ§€κ³  μžˆλ‹€."

 

정말 κ·Έ μ–΄λ–€ μ˜ˆμ‹œλ³΄λ‹€ 졜고의 μ˜ˆμ‹œμΈκ²ƒ κ°™λ„€μš”. λ°°μš°λŠ” λ°°μš°μ—λ§Œ λͺ°λ‘ν•΄μ•Όν•©λ‹ˆλ‹€. 곡연 μž₯μ†Œλ₯Ό μ •ν•˜κ³ , μ—­ν• μ—λŠ” λˆ„κ΅΄ μΊμŠ€νŒ… 할지에 λŒ€ν•΄μ„œλŠ” λ°°μš°κ°€ μ•„λ‹Œ [곡연 기획자]κ°€ κ²°μ •ν•΄μ•Ό ν•˜λŠ” λΆ€λΆ„μž…λ‹ˆλ‹€. μš°λ¦¬λŠ” 이런 역할을 해쀄 [곡연 기획자]κ°€ ν•„μš”ν•©λ‹ˆλ‹€.

 

그리고 μžλ°”μ—μ„œλŠ” [곡연 기획자]λ₯Ό AppConfigλΌλŠ” ν΄λž˜μŠ€κ°€ λ‹΄λ‹Ήν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

public class AppConfig {

    public Driver driver(){
        return new DriverImpl(car(), engine());
    }

    public Car car(){
        return new K3();
    }

    public Engine engine(){
        return new Electronic();
    }

}

 

μœ„ AppConfigλŠ” 순수 μžλ°”λ‘œλ§Œ κ΅¬μ„±λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. μŠ€ν”„λ§μ—μ„œ μ œκ³΅λ˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜μ€ μ‚¬μš©λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. μŠ€ν”„λ§μœΌλ‘œ ν•΄κ²°ν•˜λŠ” 방법은 λ‹€μŒ κΈ€μ—μ„œ μ§„ν–‰ν•˜κ² μŠ΅λ‹ˆλ‹€.

 

AppConfigμ—μ„œ Car μ—­ν• (μΈν„°νŽ˜μ΄μŠ€)λ‘œλŠ” μ–΄λ–€ κ΅¬ν˜„μ²΄λ₯Ό μ‚¬μš©ν•  것인지, Engine μ—­ν• (μΈν„°νŽ˜μ΄μŠ€)λ‘œλŠ” μ–΄λ–€ κ΅¬ν˜„μ²΄λ₯Ό μ‚¬μš©ν•  것인지 μ£Όμž…ν•΄μ€˜μ•Ό ν•©λ‹ˆλ‹€. 그리고 Driver μ—­ν• (μΈν„°νŽ˜μ΄μŠ€)을 μƒμ„±μžλ₯Ό 톡해 μ™ΈλΆ€μ—μ„œ 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.

 

public class DriverImpl implements Driver{

    private final Car car;//μ—­ν• λ§Œ μ•Œλ €μ£Όκ³  κ΅¬ν˜„μ²΄λŠ” 무엇인지 μ•Œλ €μ€„ ν•„μš”κ°€ μ—†λ‹€.
    private final Engine engine;

    public DriverImpl(Car car, Engine engine) {
        this.car = car;//역할을 μ •ν•΄μ€€λ‹€.
        this.engine = engine;//역할을 μ •ν•΄μ€€λ‹€.
    }

    @Override
    public void findOwnCarDetail() {
        car.findCarName();
        car.findCarBrand();
        engine.WayToMove();
    }
}

 

Driver κ΅¬ν˜„μ²΄λ₯Ό μœ„μ™€ 같이 바꿔쀄 수 μžˆμŠ΅λ‹ˆλ‹€. 이전 μ½”λ“œμ—μ„œλŠ” new K3(), new Fuel() μ΄λŸ°μ‹μœΌλ‘œ 직접 역할을 μ§€μ •ν•΄μ£Όμ—ˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μœ„ μ½”λ“œλŠ” μžλ°”κ°€ 이λ₯Ό μ•Œμ•„μ„œ μ£Όμž…μ„ μ‹œμΌœμ€λ‹ˆλ‹€.

 

μ΄μ „μ—μ„œλŠ” κ΅¬ν˜„μ²΄μ— 직접 K3, Fuel μ§€μ •ν•΄μ£Όμ—ˆλ‹€. ν•œλ§ˆλ””λ‘œ κ΅¬ν˜„ 객체가 ν”„λ‘œκ·Έλž¨μ˜ μ œμ–΄ 흐름을 슀슀둜λ₯Ό μ‘°μ’…ν–ˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ AppConfigλ₯Ό μƒμ„±ν•œ λ’€λ‘œλŠ” κ΅¬ν˜„ κ°μ²΄λŠ” μ—­ν• (μΈν„°νŽ˜μ΄μŠ€)λ“€λ§Œ ν˜ΈμΆœν•˜μ§€, κ΅¬ν˜„μ²΄μ— λŒ€ν•΄μ„œλŠ” ν˜ΈμΆœν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. Driver κ΅¬ν˜„ κ°μ²΄λŠ” Car, Engineμ΄λΌλŠ” 역할에 μ–΄λ–€ κ΅¬ν˜„μ²΄κ°€ μ£Όμž…λ  κ²ƒμΈμ§€λŠ” μ „ν˜€ μ•Œ 수 μ—†μ£ .

 

이렇듯 ν”„λ‘œκ·Έλž¨μ— λŒ€ν•œ μ œμ–΄ 흐름을 μ™ΈλΆ€κ°€ μ•„λ‹Œ AppConfigκ°€ κ°€μ§€κ²Œ λ˜λŠ”λ° 이λ₯Ό [μ œμ–΄μ˜ μ—­μ „(IoC, Inversion of Control)]이라고 ν•©λ‹ˆλ‹€. λ˜ν•œ AppConfigκ°€ κ΅¬ν˜„ 객체λ₯Ό μ£Όμž…μ‹œμΌœμ£ΌλŠ” 것을 [μ˜μ‘΄κ΄€κ³„ μ£Όμž…(DI, Dependency Injection)]라고 ν•©λ‹ˆλ‹€.

 

그리고 AppConfig처럼 객체λ₯Ό μƒμ„±ν•˜κ³  κ΄€λ¦¬ν•˜λ©΄μ„œ μ˜μ‘΄κ΄€κ³„λ₯Ό μ—°κ²°ν•΄μ£ΌλŠ” 것을 DI μ»¨ν…Œμ΄λ„ˆ(IoC μ»¨ν…Œμ΄λ„ˆ)라고 ν•©λ‹ˆλ‹€.

 

public class DrivingApp {
    public static void main(String[] args) {
        AppConfig appConfig = new AppConfig();

        Driver driver = appConfig.driver();
        driver.findOwnCarDetail();
    }
}

이런 μ‹μœΌλ‘œ μ•Œμ•„μ„œ 객체가 μ•Œμ•„μ„œ μ£Όμž…λ˜λ―€λ‘œ 외뢀에선 AppConfigλ₯Ό 보지 μ•ŠλŠ” ν•œ μ–΄λ– ν•œ 역할에 μ–΄λ–€ 객체λ₯Ό μ‚¬μš©ν•˜λŠ” μ§€ μ•Œμˆ˜ μ—†μ£ . μ•Œ ν•„μš”λ„ μ—†μ£ . μš°λ¦¬κ°€ μš΄μ „ν•˜λŠ”λ° μžˆμ–΄μ„œ μš΄μ „ν•˜λŠ” λ°©λ²•λ§Œ μ•Œλ©΄ λ˜μ§€ 엔진이 μ–΄λ–»κ²Œ μž‘λ™ν•˜κ³ , λ°”ν€΄λŠ” μ–΄λ–»κ²Œ κ΅΄λŸ¬κ°€λŠ” μ§€ μ•Œ ν•„μš”λŠ” μ—†μž–μ•„μš”? ν•˜λ¬Όλ©° μžλ™μ°¨λ§ˆλ‹€ μ—”μ§„μ˜ μ’…λ₯˜κ°€ λ‹€λ₯Έλ° κ·Έκ±° λͺ°λΌλ„ μš΄μ „λ§Œ 잘 ν•˜μž–μ•„μš”. 

 

λ§Œμ•½ K3 μ „κΈ°μ°¨κ°€ μ•„λ‹Œ K5 μ—°λ£Œμ°¨λ‘œ λ°”κΎΈκ³  μ‹Άλ‹€λ©΄ AppConfig의 μ½”λ“œλ§Œ μˆ˜μ •ν•˜λ©΄ λ©λ‹ˆλ‹€.

public class AppConfig {

    public Driver driver(){
        return new DriverImpl(car(), engine());
    }

    public Car car(){
        return new K5();
    }

    public Engine engine(){
        return new Fuel();
    }

}

μ½”λ“œμ—μ„œ μ•Œ 수 μžˆλ“―μ΄ Driver κ΅¬ν˜„μ²΄μ— 더 이상 μ§μ ‘μœΌλ‘œ 객체λ₯Ό μƒμ„±ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. κ΅¬ν˜„μ²΄μ— μ˜μ‘΄ν•˜μ§€ μ•Šμ£ . λ˜ν•œ μ „κΈ°λ₯Ό μ—°λ£Œλ‘œ λ°”κΏ€ λ•Œ κ΅¬ν˜„μ²΄μ˜ μ½”λ“œλ₯Ό μ§μ ‘μ μœΌλ‘œ μˆ˜μ •ν•  ν•„μš”λ„ μ—†μŠ΅λ‹ˆλ‹€. AppConfigλΌλŠ” [곡연 기획자]κ°€ λ‹€ ν•΄μ£Όλ‹ˆκΉμš”.

 

이번 κΈ€μ—μ„œ AppConfigλΌλŠ” DI μ»¨ν…Œμ΄λ„ˆλ₯Ό μ΄μš©ν•΄μ„œ OCP와 DIPλ₯Ό ν•΄κ²°ν•΄ λ³΄μ•˜μŠ΅λ‹ˆλ‹€. μ§€κΈˆ λ‹Ήμž₯은 μ½”λ“œ μˆ˜κ°€ 적기 λ•Œλ¬Έμ— AppConfigλ₯Ό λ§Œλ“€μ–΄μ„œ μ—¬κΈ°λ‹€κ°€ μ„ μ–Έν•˜λŠ” 것이 μ–΄λ ΅μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ½”λ“œλŸ‰μ΄ λ§Žμ•„μ§ˆ 경우 AppConfig둜만 κ΄€λ¦¬ν•˜κΈ° νž˜λ“€μ–΄μ§‘λ‹ˆλ‹€.

 

λ”°λΌμ„œ λ‹€μŒ κΈ€μ—μ„œλŠ” μŠ€ν”„λ§μ„ μ‚¬μš©ν•˜μ—¬ OCP와 DIPλ₯Ό ν•΄κ²°ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€. μ–΄λŠ 정도 μ™œ μŠ€ν”„λ§μ„ μ‚¬μš©ν•˜λŠ” μ§€ μ§μž‘μ΄ κ°€μ‹œμ£ ?