
1) ๊ณ ๊ธ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ(OOP)๋? ๐งฑ
- ๊ฐ์ฒด(Object): ๋ฐ์ดํฐ(ํ๋) + ํ๋(๋ฉ์๋)์ ๋ฌถ์ ๋จ์
- ์บก์ํ, ์์, ๋คํ์ฑ, ์ถ์ํ๊ฐ ๊ธฐ๋ณธ 4์์
- “๊ณ ๊ธ” OOP๋ ๋ค์์ ๋ ์ ๊ฒฝ ์๋๋ค :
โ ์ธํฐํ์ด์ค(Interface)/์ถ์ํด๋์ค(Abstract Class) ์ค์ฌ ์ค๊ณ
→ ๊ตฌํ(Concrete)์ ๊ฐ์๋ผ์ฐ๊ธฐ ์ฝ๊ฒ
| ์ธํฐํ์ด์ค (Interface) | ์ถ์ ํด๋์ค (Abstract Class) |
|
|
โป ํจ์ ์๊ทธ๋์ฒ (method signature)
- ๋ฉ์๋๋ฅผ ์๋ณํ๋ “์ด๋ฆ + ๋งค๊ฐ๋ณ์(parameter, ํ์ ๊ณผ ์์)”์ ์กฐํฉ.
- return type๊ณผ throws ์ ์ ์ ์ธ
| “throws ์ (throws clause)” = ๋ฉ์๋ ์ ์ธ์์ “์ด ๋ฉ์๋๊ฐ ๋์ง ์ ์๋ ‘์ฒดํฌ ์์ธ’ ๋ชฉ๋ก”์ ์ ์ธํ๋ ๋ถ๋ถ. ๊ตฌํ/์ค๋ฒ๋ผ์ด๋ ์ ๋ ๋์(์์) ์ฒดํฌ ์์ธ๋ก ํ๋ํ๋ฉด ์ ๋๊ณ , ๊ฐ๊ฑฐ๋ ๋ ์ขํ์ผ ํ๋ค. |
// ์๊ทธ๋์ฒ: pay(int)
// ์๋ ๋ ๋ฉ์๋๋ ์ด๋ฆ๊ณผ ํ๋ผ๋ฏธํฐ๊ฐ ๊ฐ์์ ใ ๊ฐ์ ์๊ทธ๋์ฒ ใ
void pay(int amount);
int pay(int amount); // ์ปดํ์ผ ๋ถ๊ฐ(๋ฐํํ์
๋ง ๋ค๋ฅด๋ฉด ์ค๋ฒ๋ก๋ฉ ์๋)
// ์ค๋ฒ๋ก๋ฉ์ ํ๋ผ๋ฏธํฐ ๋ชฉ๋ก์ด ๋ฌ๋ผ์ผ ํจ
void pay(long amount); // pay(long) → ๋ค๋ฅธ ์๊ทธ๋์ฒ
void pay(int amount, int tax); // pay(int,int) → ๋ค๋ฅธ ์๊ทธ๋์ฒ
โ ๏ธ ์ธํฐํ์ด์ค ๊ตฌํ ์์๋ ๋ฐํ ํ์ ์ด ํธํ๋์ด์ผ ํ๋ค (๋์ผ ํน์ ๊ณต๋ณ ๋ฐํ ํ์ )
= ์ธํฐํ์ด์ค ๋ฉ์๋๋ฅผ ๊ตฌํ(override)ํ ๋ ๋ฐํ ํ์ ์ ๊ฐ๊ฒ ํ๊ฑฐ๋ “๋ ๊ตฌ์ฒด์ ์ธ(subtype)/ํ์ ํ์ ”์ผ๋ก ๋ฐ๊ฟ๋ ๋๋ค.
interface Repo {
Number findId(); // ๊ณ์ฝ: Number๋ฅผ ๋ฐํ
}
class IntRepo implements Repo {
@Override
public Integer findId() { // OK: Integer๋ Number์ ํ์ ํ์
→ ๊ณต๋ณ ๋ฐํ
return 42;
}
}
class BadRepo implements Repo {
@Override
public Object findId() { // ์ปดํ์ผ ์๋ฌ: Object๋ Number์ ์์ ํ์
(๋
โป ์ํ (์ธ์คํด์ค ํ๋)
- ๊ฐ์ฒด(instance, ํด๋์ค=๊ฐ์ฒด์ ์์ฑ์ ์ ์, ๊ธฐ๋ฅ์ ๊ตฌํํด๋์ ์ฝ๋ ์ํ)๊ฐ ๊ฐ๋ณ์ ์ผ๋ก ๊ฐ์ง๊ณ ์๋ ๋ฐ์ดํฐ(ํ๋, field).
- ์ธ์คํด์ค๋ง๋ค ๊ฐ์ด ๋ค๋ฅผ ์ ์์.
- ์: ์ํ ๊ณ์ข ๊ฐ์ฒด๋ง๋ค balance๊ฐ ๋ค๋ฆ → balance๊ฐ “์ธ์คํด์ค ํ๋(์ํ)”.
class BankAccount {
private int balance; // ์ธ์คํด์ค ํ๋(์ํ)
public void deposit(int amount) { balance += amount; }
}
https://lala9663.tistory.com/31
[์๋ฐ] ์ธ์คํด์ค(Instance)๋?
์ธ์คํด์ค(instance) ํด๋์ค๋ ๊ฐ์ฒด์ ์์ฑ์ ์ ์ํ๊ณ , ๊ธฐ๋ฅ์ ๊ตฌํํ์ฌ ๋ง๋ค์ด ๋์ ์ฝ๋ ์ํ ์ค์ ํด๋์ค๊ธฐ๋ฐ์ผ๋ก ์์ฑ๋ ๊ฐ์ฒด(์ธ์คํด์ค)๋ ๊ฐ๊ฐ ๋ค๋ฅธ ๋ฉค๋ฒ ๋ณ์ ๊ฐ์ ๊ฐ์ง๊ฒ ๋จ ๊ฐ๋ น, ํ์์
lala9663.tistory.com
| ์ค์ ํด๋์ค๊ธฐ๋ฐ์ผ๋ก ์์ฑ๋ ๊ฐ์ฒด(์ธ์คํด์ค)๋ ๊ฐ๊ฐ ๋ค๋ฅธ ๋ฉค๋ฒ ๋ณ์ ๊ฐ์ ๊ฐ์ง๊ฒ ๋จ ๊ฐ๋ น, ํ์์ ํด๋์ค์์ ์์ฑ๋ ๊ฐ๊ฐ์ ์ธ์คํด์ค๋ ๊ฐ๊ฐ ๋ค๋ฅธ ์ด๋ฆ, ํ๋ฒ, ํ๋ ๋ฑ์ ๊ฐ์ ๊ฐ์ง๊ฒ ๋จ new ํค์๋๋ฅผ์ฌ์ฉํ์ฌ ์ธ์คํด์ค ์์ฑ |
โป default/static(์ ์ ) ๋ฉ์๋
Java 8+์์ ์ธํฐํ์ด์ค๋ ๋ฉ์๋์ “๊ธฐ๋ณธ ๊ตฌํ”์ ๊ฐ์ง ์ ์์ต๋๋ค.
- default ๋ฉ์๋
- ์ธํฐํ์ด์ค์ ๊ตฌํ ์ฝ๋๋ฅผ ๋ ์ ์๊ฒ ํด ์ฃผ๋ ํค์๋.
- ๊ตฌํ ํด๋์ค๋
- ๊ทธ๋๋ก “์์ํด ์ฌ์ฉ”ํ๊ฑฐ๋,
- ํ์ํ๋ฉด “override(์ฌ์ ์)”ํ ์ ์์.
- ํจ๊ณผ: ๊ธฐ์กด ์ธํฐํ์ด์ค์ ์ ๋ฉ์๋๋ฅผ ์ถ๊ฐํด๋, ๊ธฐ๋ณธ ๊ตฌํ์ด ์์ผ๋ ์ ๊ตฌํ์ฒด๋ค์ด ์ฆ์ ๊นจ์ง์ง ์์(ํธํ์ฑ ์ ์ง).
- static ๋ฉ์๋
- ์ธํฐํ์ด์ค ์ด๋ฆ์ผ๋ก ํธ์ถํ๋ “์ ํธ๋ฆฌํฐ ๋ฉ์๋”.
- ์ธ์คํด์ค(๊ตฌํ ํด๋์ค์ ๊ฐ์ฒด)๊ฐ ์๋๋ผ “์ธํฐํ์ด์ค ์์ฒด”์ ์ํ๋ฉฐ, ๊ตฌํ ํด๋์ค์ ์์๋์ง ์์ต๋๋ค.
๋ค์ค ์์ (Multiple Inheritance)
- ํ Class๊ฐ ์ฌ๋ฌ ๋ถ๋ชจ Class๋ฅผ ๋์์ ์์ํ๋ ๊ฒ
- ๋ค์ด์๋ชฌ๋ ๋ฌธ์ ๋ฐ์ ๊ฐ๋ฅ
(๋ค์ค ์์ ์ ์์ ๊ณตํต ์กฐ์์ด ์ค๋ณต/๋ชจํธํ๊ฒ ์์๋์ด ์ด๋ ๊ฒฝ๋ก์ ๋ฉค๋ฒ๋ฅผ ์จ์ผ ํ๋์ง ์ ๋งคํด์ง๋ ๋ฌธ์ )
์์ :
๋ค์ด์๋ชฌ๋ ๋ฌธ์ ๋ฐ์
struct A { void hello(); };
struct B : A {};
struct C : A {};
struct D : B, C {};
int main() {
D d;
// d.hello(); // ๋ชจํธ์ฑ ์ค๋ฅ: 'A::hello'๊ฐ ๋ ๊ฒฝ๋ก๋ก ์กด์ฌ
}
๋ค์ด์๋ชฌ๋ ๋ฌธ์ ํด๊ฒฐ (๊ฐ์ ์์ Virtual Inheritance๋ก A๋ฅผ ๋จ 1๋ฒ๋ง ๊ณต์ )
struct A { void hello(); };
struct B : virtual A {};
struct C : virtual A {};
struct D : B, C {};
int main(){ D d; d.hello(); } // OK, A๊ฐ ํ๋๋ก ๊ณต์ ๋จ
- JAVA๋ ๋ค์ค ์์ ์ง์ ์ ํจ. ๋์ ๋ค์ค ์์ ํจ๊ณผ๋ฅผ ์ธํฐํ์ด์ค๋ฅผ ์ด์ฉํด์ ๊ตฌํ ๊ฐ๋ฅ!!
๐ Type์ ๋ค์ค(์ฌ๋ฌ Interface)์ผ๋ก ๋ฐ๊ณ , ๊ตฌํ์ ํฉ์ฑ/์์ + ํ์ ์ default ๋ฉ์๋ ๋ณด์กฐํ๋ ๋ฐฉ์


์์ :
1. ์ฌ๋ฌ Interface๋ฅผ ํ Class๊ฐ ๋์์ ๊ตฌํ
interface Cacheable { void put(String k, String v); String get(String k); }
interface Retriable { void withRetry(Runnable r); }
class Service implements Cacheable, Retriable {
// ๊ตฌํ์ 'ํฉ์ฑ'์ผ๋ก ๋นผ์ ์ฌ์ฌ์ฉ
private final Cache cache = new Cache(); // ๋ณ๋ ๊ตฌํ์ฒด
private final RetryPolicy retry = new RetryPolicy();
@Override public void put(String k, String v){ cache.put(k,v); }
@Override public String get(String k){ return cache.get(k); }
@Override public void withRetry(Runnable r){ retry.runWithRetry(r); }
}
2. Interface default method๋ก ๊ฐ๋ฒผ์ด ๊ตฌํ ์๊ธฐ (Java 8+)
interface Logger {
default void log(String m){ System.out.println("[L] " + m); }
}
interface Auditor {
default void log(String m){ System.out.println("[A] " + m); }
}
class Service implements Logger, Auditor {
// ์ถฉ๋ ์ ๋ฐ๋์ ๋ช
์์ ์ผ๋ก ํด๊ฒฐ
@Override public void log(String m){ Logger.super.log(m); }
}
โก ํฉ์ฑ(Composition) ์ฐ์ → “is-a” ์์๋ณด๋ค “has-a” ์กฐ๋ฆฝ์ ์ ํธ
"is-a" ์์(inheritance) : A๋ B์ ํ ์ข ๋ฅ์ด๋ค.
- ์์์ field, method๋ฅผ ๋ฌผ๋ ค๋ฐ๋๋ค(์ฌ์ฌ์ฉ) + overiding์ผ๋ก ํนํ
- type ๊ณ์ธต์ผ๋ก ๋คํ์ฑ(polymorphism) ํ์ฉ
- ๊ฐํ ๊ฒฐํฉ, ๋ฎ์ ์ ์ฐ์ฑ
- ์ทจ์ ๊ฐ๋ฅํ(์ ๋งคํ) ๊ด๊ณ์ ์ฐ์ด๋ฉด LSP ์๋ฒ, bug ์ ๋ฐ
์์ :
class Animal { void move() {} }
class Dog extends Animal { @Override void move() { /* ๊ฑท๊ธฐ */ } }
"has-a" ์กฐ๋ฆฝ(composition) : A๋ B๋ฅผ ๊ฐ์ง๋ค. A๋ B๋ฅผ ์ฌ์ฉํด ์์ง์ธ๋ค.
- ๊ฐ์ฒด๊ฐ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์์ฑ์ผ๋ก ๊ฐ์ง๊ณ , ๊ทธ ๊ฐ์ฒด์๊ฒ ์ผ์ ์์(delegate)ํด ๊ธฐ๋ฅ์ ์ด๋ฃฌ๋ค.
- ๋ด๋ถ์ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ field๋ก ๋๋ค.
- ๋์จํ ๊ฒฐํฉ
์์ :
interface Payment { void pay(int amount); }
class Card implements Payment { public void pay(int a){ /*...*/ } }
class Kakao implements Payment { public void pay(int a){ /*...*/ } }
class Checkout { // has-a Payment
private Payment payment;
Checkout(Payment p){ this.payment = p; }
void setPayment(Payment p){ this.payment = p; } // ๋ฐํ์ ๊ต์ฒด
void process(int amount){ payment.pay(amount); } // ์์
}
์ผ๋ฐํ๋ ์์ํ?
์ผ๋ฐํ๋ "is a kind of" ๊ด๊ณ์ด๋ค.

โข ๋์จํ ๊ฒฐํฉ(Loosely Coupled)๊ณผ ์์กด์ฑ ์ฃผ์ (DI) → ํ ์คํธ/๊ต์ฒด ์ฉ์ด
โฃ SOLID ์์น ์ค์ → ํ์ฅ์ ์ด๋ ค ์๊ณ ๋ณ๊ฒฝ์ ๋ซํ ์๊ฒ(Open-Closed)
https://lxvxxu.tistory.com/1336
[Java] ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ(OOP) - 4. SOLID๋?
lxvxxu.tistory.com
๊ฒฐ๊ตญ ๋ชฉํ๋ “๋ณํ์ ๊ฐํ ์ฝ๋”.
์๊ตฌ์ฌํญ์ด ๋ฐ๋์ด๋ ์์ ๋ฒ์๋ฅผ ์ต์ํํ๊ณ ,
ํ ์คํธ๊ฐ ์ฌ์ด ๊ตฌ์กฐ๋ฅผ ๋ง๋๋ ๊ฒ์ ๋๋ค.