์ ์๊ธฐ๋ฅ์์กด์ฑ ์ญ์ (Dependency Inversion)๋ถ๊ฐ ๊ธฐ๋ฅ๋ํดํธ ๋ฉ์๋๋๋ค์๋๋ค์ ์ฌ์ฉ ์, ์ฃผ์์ ๋ฉ์๋ ๋ ํผ๋ฐ์ค์ ๋๋ฆญ์ต๋ช
ํด๋์คprivate ๋ฉ์๋์ธํฐํ์ด์ค use-case๋ค์ค ์ธํฐํ์ด์ค ๊ตฌํStatic fields and methods
์ ์
- ๋ชจ๋ ๋ฉ์๋๊ฐ ์ถ์๋ฉ์๋๋ก ์ ์ธ๋จ public abstract(์๋ฌด๊ฒ๋ ๋ถ์ด์ง ์์๋) โ Class์์ implements์ public ์๋ถ์ฌ์ฃผ๋ฉด ์๋ฌ๊ฐ ์๊น
- ๋ชจ๋ ๋ณ์๊ฐ ์์๋ก ์ ์ธ๋จ public static final
- ๊ตฌํ ์ฝ๋๊ฐ ์์ผ๋ฏ๋ก, ์์์ด ์๋ Calculator๊ฐ Calc๋ฅผ ๊ตฌํํ๋ค๊ณ (Class Diagram์์ ์ ์ ) ํจ

- CompleteCalc๊ฐ Calc๋ฅผ ํ์ ์์ํ๋ค ๋ผ๊ณ ๋งํจ. ๊ตฌํ์์๊ณผ๋ ๋ค๋ฆ(๊ตฌํ ์ฝ๋๋ฅผ ๋ฐ์๊ฒ)
Calc calc = new CompleteCalc();
๊ฐ๋ฅํจ- ๊ตฌํ์์์ ์ฌ๋ฌ ํด๋์ค๋ฅผ ๋ค์ค์์ํ ์์์(๋ชจํธ์ฑ ์กด์ฌ) โ diamond problem
- ํ์ ์์์ ์ฌ๋ฌ ํด๋์ค๋ฅผ implements๋ฅผ ํ ์ ์์(๋ชจํธ์ฑ์ด ์์. ์ด์ฐจํผ ๊ตฌํ๋๊ฒ์ด ์๊ธฐ์)

๊ธฐ๋ฅ
- ์ผ์ข ์ ํด๋ผ์ด์ธํธ ์ฝ๋์์ ์ฝ์์ด๋ฉฐ, ํด๋์ค๋ ํ๋ก๊ทธ๋จ์ด ์ ๊ณตํ๋ ๋ช ์ธ
- ์ด๋ค ๊ฐ์ฒด๊ฐ ํ๋์ ์ธํฐํ์ด์ค ํ์ ์ด๋ผ๋ ๊ฒ์ ๊ทธ ์ธํฐํ์ด์ค๊ฐ ์ ๊ณตํ๋ ๋ชจ๋ ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ค๋ ์๋ฏธ = ๊ตฌํ์ ๊ฐ์ ํจ
- ๋คํ์ฑ์ ์ ๊ณตํจ
์์กด์ฑ ์ญ์ (Dependency Inversion)
- ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๋ ํจ๊ณผ (์์กด์ฑ์ ์ญ์ )
public class Main{ public static void Main(String[] args){ new Main().run(LoginType.Naver); // LoginType - Enum } void run(LoginType loginType){ Login user = getLogin(loginType); user.login(); } // ์ด๊ฒ factory ํจํด์ private Login getLogin(LoginType type){ if (type == LoginType.Naver) return new NaverLogin(); return new KakaoLogin(); } }
public class UserService implements Login { private Login login; // ์์กด์ฑ์ ์ธ๋ถ์ ๋งก๊ธด๋ค๋ฉด, ์์กด๋์จ ๋ฎ์ถค // KakaoLogin, NaverLogin ๋ฑ์ ๊ตฌ์์ฒด๋ฅผ ์ ์ธํ๊ฒ ๋๋ฉด // ๊ฒฐํฉ์ฑ์ด ๋์์ง๋ ๊ฒ์ ์ถ์์ฒด์ ๊ฒฐํฉ์ ํจ => ๊ฒฐํฉ๋๊ฐ ๋ฎ์์ง // ์์กด์ฑ์ ์ธ๋ถ๋ก๋ถํฐ ์ ๋ฌ ๋ฐ์๋ค => ์์กด์ฑ์ ์ฃผ์ ๋ฐ์๋ค // ์์กด์ฑ ์ฃผ์, Dependency Injection, DI // Dependency Inversion ๋จ (์ด๋๊ฐ์ ์์กดํ๊ฒ ๋ ๋, ๊ตฌ์์ฒด์ ์์กดํ์ง ๋ง๊ณ // ์ถ์์ฒด์ ์์กดํด๋ผ. ์์กด์ฑ์ ์ญ์ ํด์ ์์กดํ๋ ๊ฒ์) public UserService(Login login){ this.login = login; } @Override public void login() { login.login(); } }

- ์ด ๋ชจ๋์ด ๋ฌด์จ ์ผ์ ํ๋ ์ง์ ๋ํ ๋ช ์ธ. ์ธ ๋ ๊ทธ๊ฒ ์ด๋ป๊ฒ ๋์๊ฐ๋์ง ์ ํ์๊ฐ ์์ผ๋ ์ด๋ interface๊ฐ ๋งค์ฐ ํฐ ์ญํ ์ ํจ. ํธ์ถํ๋ ์ชฝ์์๋ ์ฐ๋ ๋ฐฉ์์ด ๋๊ฐ์
๋ถ๊ฐ ๊ธฐ๋ฅ
๋ํดํธ ๋ฉ์๋
- ์ธํฐํ์ด์ค๊ฐ ์ถ์ ๋ฉ์๋๊ฐ ์๋ ์ผ๋ฐ ๋ฉ์๋๋ฅผ ๊ฐ์ง ์ ์๋๋ก ํด์ค
- Adapter์ ์ญํ ์ ํ๊ฒ ๋จ(Adapter๋ interface์์ ์๋ ๋ชจ๋ ๋ฉ์๋๋ฅผ ๊ตฌํํ ํ์ ์๊ฒ ๋ง๋ค๊ธฐ ์ํ์ฌ ์ค์ ์ด์ฉํ๋ ํด๋์ค์ interface ์ฌ์ด์ ํ๋ ๋ ์ถ๊ฐํ๋ ๊ฒ) โ default ๋ฉ์๋๋ฅผ ํตํด Adapter๊ฐ ํ์ ์๊ฒ ๋จ
public interface MyInterface{ void method1(); void method2(); default int method3() { return 42; } } public MyInterfaceAdapter implements MyInterface{ @Override void method1(); @Override void method2(); } public MyService implements MyInterface{ } // ์ด ์ํฉ์์ MyService๋ method1๋ง ์ฐ๊ณ ์ถ์๋ฐ // ๋ชจ๋ ๋ฉ์๋๋ฅผ ๊ตฌํํด์ผ ํ๋ ์ํฉ์ ๋์ด๊ฒ ๋จ // ์ด ๋, MyInterface์ default๋ฅผ ๋ค ๋ถ์์ผ๋ก์จ // ์ฌ์ฉํ๋ ค๋ ๋ฉ์๋๋ง overrideํด์ ์ฌ์ฉ์ด ๊ฐ๋ฅํจ
- ์ธํฐํ์ด์ค ์ถ๊ฐ ๋ง์ผ๋ก ๊ธฐ๋ฅ์ ํ์ฅํ ์ ์์(default ๋ฉ์๋๋ก ๊ธฐ๋ฅ์ด ๊ตฌํ๋์ด ์๊ธฐ ๋๋ฌธ์)
๋๋ค์
- ๋ฉ์๋๋ ์ต๋ช ์ผ๋ก ๋ง๋ค ์ ์์ง ์์๊น ํ๋ ์๊ฐ์์ ์ถ๋ฐ
- ๋ด๋ถ์ ์ผ๋ก๋ ์ต๋ช ํด๋์ค๊ฐ ๋ง๋ค์ด์ง๋ ๊ตฌ์กฐ์
MyRunnable r1 = new MyRunnable(){ @Override public void run(){ System.out.println("Hello"); }; } MyRunnable r2 = () -> System.out.println("Hello"); // ๋๋คํํ์(์ต๋ช ๋ฉ์๋) // FunctionalInterface์ผ๋๋ง ์ด๋ฐ์์ผ๋ก ์ ์ธ์ด ๊ฐ๋ฅํจ. // ๊ตฌํ๋ถ๊ฐ ํ์ค ๋ฐ์์์ผ๋ฉด {} ์ด๊ฒ๋ ์๋ต ๊ฐ๋ฅํจ // ํ๋ผ๋ฏธํฐ๊ฐ ํ๊ฐ๋ฉด () ๋ ์๋ต ๊ฐ๋ฅํจ // ๋ค FunctionalInterface์ MySupplier s = () -> "Hello World"; MyMapper m = (str) -> str.length(); // Method reference๋ก ๋ณ๊ฒฝ ๊ฐ๋ฅํจ // MyMapper m = String::length; MyConsumer c = i -> System.out.println(i); // System.out::println; MyRunnable r = () -> c.consume(m.map(s.supply())); // FunctionalInterface ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ void loop(int n, MyConsumer<Integer> consumer){ for(int i=0; i< n; i++){ consumer.consume(i); } } loop(10, System.out::println);
๋๋ค์ ์ฌ์ฉ ์, ์ฃผ์์
int strike = 0; int ball = 0; answer.indexedForEach((num, idx) -> { numbers.indexedForEach((num2, idx2) -> { if(!num.equals(num2)) return; if(idx.equals(idx2)) strike++; else ball++; }); });
- FunctionalInterface ์์์ ๋ฐ๊นฅ์ ๋ณ์๋ฅผ ์ฝ์ด์ฌ ์๋ ์์ง๋ง ๊ทธ ๋ณ์๋ฅผ ์์ ํ ์๋ ์์. โ ThreadSafe ํ์ง ์์
- MultiThread์์ IndexedForEach๋ฅผ ํตํด์ ๊ฐ์ ๋ณ๊ฒฝ์ด ์๊ฒ ๋๋ฉด RaceCondition์ด ์ผ์ด๋๊ฒ ๋จ
- ๋๊ธฐํ ๊ธฐ๋ฅ์ ์ถ๊ฐํด ์ฃผ์ด์ผํจ(AtomicInteger ์ฌ์ฉ)
public BallCount ballCount(Numbers answer, Numbers numbers){ AtomicInteger strike = new AtomicInteger(); AtomicInteger ball = new AtomicInteger(); answer.indexedForEach((num, idx) -> { numbers.indexedForEach((num2, idx2) -> { if(!num.equals(num2)) return; if(idx.equals(idx2)) strike.getAndIncrement(); else ball.getAndIncrement(); }); }); }
๋ฉ์๋ ๋ ํผ๋ฐ์ค
- ๋๋ค ํํ์์์ ์ ๋ ฅ๋๋ ๊ฐ์ ๋ณ๊ฒฝ ์์ด ๋ฐ๋ก ์ฌ์ฉํ๋ ๊ฒฝ์ฐ (๊ฐ๋ฐ์์ ๊ฐ์ ์ ์ฐจ๋จํจ์ผ๋ก์จ ์์ ์ฑ์ ์ป์ ์ ์์. ๋ณ๊ฒฝํ์ง ๋ง๊ณ ๊ทธ๋๋ก ์ฌ์ฉํ๋ผ๋ ์์ง์ ํํ!!)
- ์ต์ข ์ผ๋ก ์ ์ฉ๋ ๋ฉ์๋์ ๋ ํผ๋ฐ์ค๋ฅผ ์ง์ ํด์ฃผ๋ ํํ ๋ฐฉ์
์ ๋๋ฆญ
- ์์ ๊ฒฝ์ฐ์์ ๋ฐํ ๋๋ output, input์ ํํ๋ฅผ ๋ฐ๊พธ๊ธฐ ์ํด์๋?? Generic ์ฌ์ฉ!!
public interface MySupplier<T> { T supply(); } public interface MyMapper<IN, OUT>{ OUT map(IN); } MySupplier<String> s = () -> "Hello World"; MyMapper<String, Integer> m = String::length;
์ต๋ช ํด๋์ค
- ์ธํฐํ์ด์ค ์ด์ฉํ๋ ค๋ฉด ํญ์ ๊ตฌํ์ ํด์ผ ํ๊ธฐ์ ํด๋์ค๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค. โ ๋ถํธํด์ ํ๋ฒ์ ํ๋ ๊ฒ์ด ์ต๋ช ํด๋์ค
new Runnable(){ @Override public void run(){ //~~~~ } }.run();
private ๋ฉ์๋
- ์ธํฐํ์ด์ค ์์ default ๋ฉ์๋๊ฐ ์ฌ๋ฌ ๊ฐ ์์ ๋, private ๋ฉ์๋๋ฅผ ๋ง๋ค์ด์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํจ
interface SomeInterface { void method1(); String method2(int i); default int method3() { return getNumber(); } default int method4() { return getNumber() + 22; } private int getNumber() { return 42; } }
์ธํฐํ์ด์ค use-case
ํ๋์ ํด๋์ค๊ฐ ์ฌ๋ฌ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ์ ์์
public class A implements B, C {} ;
์ธํฐํ์ด์ค ์ฌ์ด์ ์์
public interface MyInterface extends X, Y{};
- extends ๋ค์ ์ฌ๋ฌ ๊ฐ๊ฐ ๋์ค๋ฉด ์๋ค๋ค ๋ค ์ธํฐํ์ด์ค ์ธ๊ฒ.
ํด๋์ค ์์๊ณผ ์ธํฐํ์ด์ค ๊ฐ์ด ์ฌ์ฉ(extends ๋จผ์ , implementsํ์)
public class BookShelf extends Shelf implements Queue{};
๋ค์ค ์ธํฐํ์ด์ค ๊ตฌํ
- ๋ํดํธ ๋ฉ์๋๊ฐ ์ค๋ณต ๋๋ ๊ฒฝ์ฐ๋ ๊ตฌํํ๋ ํด๋์ค์์ ์ฌ์ ์ ํ์ฌ์ผ ํจ
public interface Buy { void buy(); default void order() { System.out.println("buy order"); } } public interface Sell { void sell(); default void order() { System.out.println("sell order"); } } public class Customer implements Buy, Sell{ @Override public void sell() { System.out.println("customer sell"); } @Override public void buy() { System.out.println("customer buy"); } @Override public void order() { System.out.println("customer order"); } public void hello() { System.out.println("hello"); } }
Static fields and methods
- Java8 ์ดํ๋ถํฐ ์ธํฐํ์ด์ค ์์ ์ ์ธ๋ ๋ชจ๋ ํ๋๋ public, static, final ์ โ interface๊ฐ constant๋ฅผ ๋๊ธฐ์ ์ ํฉํ ์ฅ์๊ฐ ๋จ
- ์๋ฐ 8 ์ด์ ์๋ ์ธํฐํ์ด์ค์ ์ ์ ๋ฉ์๋ ์ ์ธ์ด ๋ถ๊ฐ๋ฅํ์(๊ทธ๋์ Companion class ๊ฐ์ ๊ฒ์ด ๋ง๋ค์ด์ก์์)
- ์๋ฐ 8 ๋ถํฐ ์ธํฐํ์ด์ค๊ฐ ์ ์ ๋ฉ์๋ ๊ฐ์ง ์ ์์. ์๋ฐ 8์์๋ public ์ ์ ๋ฉค๋ฒ๋ง ํ์ฉํ์ง๋ง, ์๋ฐ 9 ๋ถํฐ๋ private ์ ์ ๋ฉ์๋๊น์ง๋ ํ๋ฝํจ(private ๋ฉ์๋๋ ๊ฐ๋ฅํจ). ๊ทธ๋ฌ๋ ์ ์ ํ๋์ ์ ์ ๋ฉค๋ฒ ํด๋์ค๋ ์ฌ์ ํ public์ด์ด์ผ ํจ!