OOP μμΉ
OOP μμΉ¶
μ£Όμ : Programming λ μ¨: 5 of 16 μ μμ§μ: ν΄λμ€μ κ°μ²΄μ λν κΈ°λ³Έ μ΄ν΄, κ°μ²΄μ§ν₯ μΈμ΄ νλ μ΄μ μμ§ λͺ©ν: OOPμ λ€ κ°μ§ κΈ°λ₯(μΊ‘μν, μΆμν, μμ, λ€νμ±)μ λ§μ€ν°νκ³ SOLID μμΉμ μ μ©νμ¬ μ μ§λ³΄μ κ°λ₯νκ³ νμ₯ κ°λ₯ν μ½λ μμ±
μκ°¶
κ°μ²΄μ§ν₯ νλ‘κ·Έλλ°(OOP, Object-Oriented Programming)μ μ½λλ₯Ό ꡬ쑰ννλ λ°©λ²μ μλ΄νλ κΈ°λ³Έ μμΉλ€ μμ ꡬμΆλ©λλ€. μ΄λ¬ν μμΉλ€μ νΌμμ μΌλ‘κ° μλλΌ κΉμ΄ μ΄ν΄νλ κ²μ μ μ§λ³΄μ κ°λ₯νκ³ νμ₯ κ°λ₯ν μννΈμ¨μ΄λ₯Ό μμ±νλ λ° νμμ μ λλ€. μ΄ λ μ¨μμλ OOPμ λ€ κ°μ§ κΈ°λ₯, SOLID μμΉ, κ·Έλ¦¬κ³ κ° κ°λ μ μΈμ μ μ©νκ³ (νΉμ νΌν΄μΌ) νλμ§ νꡬν©λλ€.
OOPμ λ€ κ°μ§ κΈ°λ₯¶
1. μΊ‘μν(Encapsulation)¶
μΊ‘μνλ λ°μ΄ν°μ κ·Έ λ°μ΄ν°λ₯Ό μ‘°μνλ λ©μλλ₯Ό λ¨μΌ λ¨μ(ν΄λμ€) λ΄μ λ¬Άλ κ²μ΄λ©°, κ°μ²΄μ μΌλΆ μ»΄ν¬λνΈμ λν μ§μ μ κ·Όμ μ νν©λλ€.
λ°μ΄ν° μλκ³Ό μ κ·Ό μ νμ(Access Modifiers)¶
μΈμ΄λ§λ€ μΊ‘μνλ₯Ό λ€λ₯΄κ² ꡬνν©λλ€:
Java:
public class BankAccount {
private double balance; // Private: only accessible within this class
private String accountNumber;
// Public interface for controlled access
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public boolean withdraw(double amount) {
if (amount > 0 && balance >= amount) {
balance -= amount;
return true;
}
return false;
}
public double getBalance() {
return balance;
}
}
Python:
class BankAccount:
def __init__(self, account_number):
self.__balance = 0.0 # Name mangling (weak privacy)
self.__account_number = account_number
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def withdraw(self, amount):
if amount > 0 and self.__balance >= amount:
self.__balance -= amount
return True
return False
@property
def balance(self):
return self.__balance
C++:
class BankAccount {
private:
double balance;
std::string accountNumber;
public:
BankAccount(const std::string& num) : balance(0.0), accountNumber(num) {}
void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
bool withdraw(double amount) {
if (amount > 0 && balance >= amount) {
balance -= amount;
return true;
}
return false;
}
double getBalance() const {
return balance;
}
};
μ 보 μλ μμΉ(Information Hiding Principle)¶
ν΅μ¬ μμ΄λμ΄: ꡬν μΈλΆμ¬νμ μ¨κΈ°κ³ νμν κ²λ§ λ ΈμΆν©λλ€. μ΄λ₯Ό ν΅ν΄ ν΄λμ€λ₯Ό μ¬μ©νλ μ½λλ₯Ό κΉ¨λ¨λ¦¬μ§ μκ³ λ΄λΆ ꡬνμ λ³κ²½ν μ μμ΅λλ€.
λμ μ (μΊ‘μν μλ°):
public class User {
public String name; // Direct access
public List<String> permissions; // Can be modified directly
}
// Client code
user.permissions.add("ADMIN"); // Bypasses any validation
μ’μ μ:
public class User {
private String name;
private Set<String> permissions; // Use Set to prevent duplicates
public void grantPermission(String permission) {
if (isValidPermission(permission)) {
permissions.add(permission);
auditLog.log("Permission granted: " + permission);
}
}
public boolean hasPermission(String permission) {
return permissions.contains(permission);
}
private boolean isValidPermission(String permission) {
// Validation logic
return true;
}
}
2. μΆμν(Abstraction)¶
μΆμνλ 볡μ‘μ±μ μ¨κΈ°κ³ νμμ μΈ νΉμ§λ§ 보μ¬μ£Όλ κ²μ μλ―Έν©λλ€. 볡μ‘ν ꡬνμ μ¨κΈ°λ λ¨μν μΈν°νμ΄μ€λ₯Ό λ§λλ κ²μ λλ€.
μΆμ ν΄λμ€ vs μΈν°νμ΄μ€¶
μΆμ ν΄λμ€ μμ (Java):
public abstract class Shape {
protected String color;
public abstract double calculateArea();
public abstract double calculatePerimeter();
// Concrete method shared by all shapes
public void setColor(String color) {
this.color = color;
}
}
public class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
@Override
public double calculatePerimeter() {
return 2 * Math.PI * radius;
}
}
public class Rectangle extends Shape {
private double width, height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double calculateArea() {
return width * height;
}
@Override
public double calculatePerimeter() {
return 2 * (width + height);
}
}
μΈν°νμ΄μ€ μμ (C++):
// Pure abstract interface
class Drawable {
public:
virtual void draw() = 0; // Pure virtual function
virtual ~Drawable() = default;
};
class Movable {
public:
virtual void move(int x, int y) = 0;
virtual ~Movable() = default;
};
// Class implementing multiple interfaces
class GameCharacter : public Drawable, public Movable {
private:
int x, y;
public:
void draw() override {
std::cout << "Drawing character at (" << x << ", " << y << ")\n";
}
void move(int newX, int newY) override {
x = newX;
y = newY;
}
};
3. μμ(Inheritance)¶
μμμ ν΄λμ€κ° λ€λ₯Έ ν΄λμ€λ‘λΆν° μμ±κ³Ό λ©μλλ₯Ό νλνμ¬ "is-a" κ΄κ³λ₯Ό ν΅ν΄ μ½λ μ¬μ¬μ©μ μ΄μ§ν©λλ€.
λ¨μΌ μμ(Single Inheritance)¶
Python:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("Subclass must implement speak()")
def sleep(self):
print(f"{self.name} is sleeping")
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
dog = Dog("Buddy")
print(dog.speak()) # Buddy says Woof!
dog.sleep() # Buddy is sleeping
λ€μ΄μλͺ¬λ λ¬Έμ (Diamond Problem, λ€μ€ μμ)¶
Python (λ€μ€ μμ μ§μ):
class A:
def method(self):
print("A")
class B(A):
def method(self):
print("B")
class C(A):
def method(self):
print("C")
class D(B, C): # Diamond inheritance
pass
d = D()
d.method() # Prints "B" (MRO: D -> B -> C -> A)
print(D.__mro__) # Shows Method Resolution Order
C++ (μ μ¬μ λ¬Έμ κ° μλ λ€μ€ μμ νμ©):
class Device {
protected:
std::string name;
};
class Printer : public Device {
public:
void print() { std::cout << "Printing...\n"; }
};
class Scanner : public Device {
public:
void scan() { std::cout << "Scanning...\n"; }
};
// Diamond problem: two copies of Device
class MultiFunctionPrinter : public Printer, public Scanner {
// Ambiguity: which 'name' to use?
};
// Solution: Virtual inheritance
class PrinterV : virtual public Device { };
class ScannerV : virtual public Device { };
class MultiFunctionPrinterV : public PrinterV, public ScannerV { };
μμμ μ¬μ©νμ§ λ§μμΌ ν λ¶
μν°ν¨ν΄:
// Inheritance used for code reuse (wrong reason)
class Stack extends ArrayList<Object> {
public void push(Object item) {
add(item);
}
public Object pop() {
return remove(size() - 1);
}
}
// Problem: Stack inherits all ArrayList methods
stack.add(0, "item"); // Can insert at arbitrary position - breaks stack contract!
λ λμ λ°©λ² (μ»΄ν¬μ§μ ):
class Stack {
private List<Object> elements = new ArrayList<>();
public void push(Object item) {
elements.add(item);
}
public Object pop() {
if (elements.isEmpty()) {
throw new EmptyStackException();
}
return elements.remove(elements.size() - 1);
}
// Only expose stack operations
}
4. λ€νμ±(Polymorphism)¶
λ€νμ±μ "λ§μ νν"λ₯Ό μλ―Ένλ©°, νλμ μΈν°νμ΄μ€μ μ¬λ¬ ꡬνμ΄ μλ κ²μ λλ€.
μ»΄νμΌ νμ λ€νμ±(Compile-Time Polymorphism, λ©μλ μ€λ²λ‘λ©)¶
Java:
class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
}
Calculator calc = new Calculator();
calc.add(5, 3); // Calls int version
calc.add(5.5, 3.2); // Calls double version
calc.add(1, 2, 3); // Calls three-argument version
λ°νμ λ€νμ±(Runtime Polymorphism, λ©μλ μ€λ²λΌμ΄λ©)¶
C++:
class PaymentProcessor {
public:
virtual void processPayment(double amount) {
std::cout << "Processing payment: $" << amount << "\n";
}
virtual ~PaymentProcessor() = default;
};
class CreditCardProcessor : public PaymentProcessor {
public:
void processPayment(double amount) override {
std::cout << "Processing credit card payment: $" << amount << "\n";
// Credit card-specific logic
}
};
class PayPalProcessor : public PaymentProcessor {
public:
void processPayment(double amount) override {
std::cout << "Processing PayPal payment: $" << amount << "\n";
// PayPal-specific logic
}
};
void checkout(PaymentProcessor* processor, double amount) {
processor->processPayment(amount); // Runtime polymorphism
}
// Usage
CreditCardProcessor creditCard;
PayPalProcessor paypal;
checkout(&creditCard, 99.99); // Uses CreditCardProcessor
checkout(&paypal, 49.99); // Uses PayPalProcessor
λ νμ΄ν(Duck Typing, λμ μΈμ΄)¶
Python:
# "If it walks like a duck and quacks like a duck, it's a duck"
class Duck:
def quack(self):
print("Quack!")
def fly(self):
print("Flying!")
class Person:
def quack(self):
print("I'm imitating a duck!")
def fly(self):
print("I'm flapping my arms!")
def make_it_quack(duck):
duck.quack() # No type checking needed
make_it_quack(Duck()) # Works
make_it_quack(Person()) # Also works!
μμλ³΄λ€ μ»΄ν¬μ§μ (Composition Over Inheritance)¶
νλ μ€κ³λ μμ(is-a)λ³΄λ€ μ»΄ν¬μ§μ (has-a)μ μ νΈνλλ°, λ μ μ°νκΈ° λλ¬Έμ λλ€.
μμ (κ²½μ§λ¨):
class Bird {
void fly() { }
}
class Penguin extends Bird {
@Override
void fly() {
throw new UnsupportedOperationException("Penguins can't fly!");
}
}
μ»΄ν¬μ§μ (μ μ°ν¨):
interface FlyBehavior {
void fly();
}
class CanFly implements FlyBehavior {
public void fly() {
System.out.println("Flying!");
}
}
class CannotFly implements FlyBehavior {
public void fly() {
System.out.println("Can't fly");
}
}
class Bird {
private FlyBehavior flyBehavior;
public Bird(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void performFly() {
flyBehavior.fly();
}
// Can change behavior at runtime
public void setFlyBehavior(FlyBehavior fb) {
this.flyBehavior = fb;
}
}
Bird eagle = new Bird(new CanFly());
Bird penguin = new Bird(new CannotFly());
SOLID μμΉ¶
S: λ¨μΌ μ± μ μμΉ(Single Responsibility Principle, SRP)¶
ν΄λμ€λ λ³κ²½ν΄μΌ ν μ΄μ κ° νλλ§ μμ΄μΌ ν©λλ€.
μλ°:
class User:
def __init__(self, name, email):
self.name = name
self.email = email
def save_to_database(self):
# Database logic (reason 1 to change)
pass
def send_welcome_email(self):
# Email logic (reason 2 to change)
pass
def generate_report(self):
# Reporting logic (reason 3 to change)
pass
μμ :
class User:
def __init__(self, name, email):
self.name = name
self.email = email
class UserRepository:
def save(self, user):
# Database logic only
pass
class EmailService:
def send_welcome_email(self, user):
# Email logic only
pass
class UserReportGenerator:
def generate(self, user):
# Reporting logic only
pass
O: κ°λ°©-νμ μμΉ(Open/Closed Principle, OCP)¶
μννΈμ¨μ΄ μν°ν°λ νμ₯μλ μ΄λ € μμ΄μΌ νμ§λ§ μμ μλ λ«ν μμ΄μΌ ν©λλ€.
μλ°:
class AreaCalculator {
public double calculateArea(Object shape) {
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
return Math.PI * circle.radius * circle.radius;
} else if (shape instanceof Rectangle) {
Rectangle rect = (Rectangle) shape;
return rect.width * rect.height;
}
// Must modify this method to add new shapes!
return 0;
}
}
μμ :
interface Shape {
double calculateArea();
}
class Circle implements Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
}
class Rectangle implements Shape {
private double width, height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public double calculateArea() {
return width * height;
}
}
class AreaCalculator {
public double calculateArea(Shape shape) {
return shape.calculateArea(); // No modification needed for new shapes
}
}
// Adding Triangle requires no changes to AreaCalculator
class Triangle implements Shape {
private double base, height;
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
@Override
public double calculateArea() {
return 0.5 * base * height;
}
}
L: 리μ€μ½ν μΉν μμΉ(Liskov Substitution Principle, LSP)¶
μλΈνμ μ νλ‘κ·Έλ¨ μ νμ±μ ν΄μΉμ§ μκ³ κΈ°λ³Έ νμ μΌλ‘ λ체 κ°λ₯ν΄μΌ ν©λλ€.
μλ°:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def set_width(self, width):
self.width = width
def set_height(self, height):
self.height = height
def area(self):
return self.width * self.height
class Square(Rectangle):
def set_width(self, width):
self.width = width
self.height = width # Maintains square invariant
def set_height(self, height):
self.width = height
self.height = height
# LSP violation
def test_rectangle(rect):
rect.set_width(5)
rect.set_height(4)
assert rect.area() == 20 # Fails for Square!
rectangle = Rectangle(0, 0)
test_rectangle(rectangle) # Pass
square = Square(0, 0)
test_rectangle(square) # Fail! area() returns 16, not 20
μμ :
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Square(Shape):
def __init__(self, side):
self.side = side
def area(self):
return self.side * self.side
# No longer substitutable, which is correctβthey're different shapes
I: μΈν°νμ΄μ€ λΆλ¦¬ μμΉ(Interface Segregation Principle, ISP)¶
ν΄λΌμ΄μΈνΈλ³ μΈλΆνλ μΈν°νμ΄μ€κ° λ²μ© μΈν°νμ΄μ€λ³΄λ€ λ«μ΅λλ€.
μλ°:
interface Worker {
void work();
void eat();
void sleep();
}
class HumanWorker implements Worker {
public void work() { /* ... */ }
public void eat() { /* ... */ }
public void sleep() { /* ... */ }
}
class RobotWorker implements Worker {
public void work() { /* ... */ }
public void eat() { /* Robot doesn't eat! */ }
public void sleep() { /* Robot doesn't sleep! */ }
}
μμ :
interface Workable {
void work();
}
interface Eatable {
void eat();
}
interface Sleepable {
void sleep();
}
class HumanWorker implements Workable, Eatable, Sleepable {
public void work() { /* ... */ }
public void eat() { /* ... */ }
public void sleep() { /* ... */ }
}
class RobotWorker implements Workable {
public void work() { /* ... */ }
// Only implements what it needs
}
D: μμ‘΄μ± μμ μμΉ(Dependency Inversion Principle, DIP)¶
μΆμνμ μμ‘΄νκ³ κ΅¬μ²΄νμ μμ‘΄νμ§ λ§μΈμ. μμ μμ€ λͺ¨λμ νμ μμ€ λͺ¨λμ μμ‘΄νμ§ μμμΌ ν©λλ€.
μλ°:
class MySQLDatabase {
public:
void save(const std::string& data) {
std::cout << "Saving to MySQL: " << data << "\n";
}
};
class UserService {
private:
MySQLDatabase database; // Tight coupling to concrete class
public:
void createUser(const std::string& username) {
database.save(username); // Can't switch databases
}
};
μμ :
// Abstraction
class Database {
public:
virtual void save(const std::string& data) = 0;
virtual ~Database() = default;
};
// Concrete implementations
class MySQLDatabase : public Database {
public:
void save(const std::string& data) override {
std::cout << "Saving to MySQL: " << data << "\n";
}
};
class PostgreSQLDatabase : public Database {
public:
void save(const std::string& data) override {
std::cout << "Saving to PostgreSQL: " << data << "\n";
}
};
// High-level module depends on abstraction
class UserService {
private:
Database* database; // Depends on abstraction
public:
UserService(Database* db) : database(db) {}
void createUser(const std::string& username) {
database->save(username); // Works with any Database implementation
}
};
// Usage
MySQLDatabase mysql;
UserService service1(&mysql);
service1.createUser("alice");
PostgreSQLDatabase postgres;
UserService service2(&postgres);
service2.createUser("bob");
λ°λ©ν λ₯΄μ λ²μΉ(Law of Demeter, μ΅μ μ§μ μμΉ)¶
"λ―μ μ΄μκ² λ§νμ§ λ§μΈμ." κ°μ²΄λ λ€μμλ§ λ©μλλ₯Ό νΈμΆν΄μΌ ν©λλ€: 1. μκΈ° μμ 2. νλΌλ―Έν°λ‘ μ λ¬λ κ°μ²΄ 3. μμ μ΄ μμ±ν κ°μ²΄ 4. μ§μ κ΅¬μ± μμμΈ κ°μ²΄
μλ°:
class Car {
private Engine engine;
public Engine getEngine() {
return engine;
}
}
class Engine {
private FuelPump fuelPump;
public FuelPump getFuelPump() {
return fuelPump;
}
}
class FuelPump {
public void pump() { }
}
// Client code
car.getEngine().getFuelPump().pump(); // Chains through three objects!
μμ :
class Car {
private Engine engine;
public void refuel() {
engine.refuel(); // Car tells Engine, doesn't reach into it
}
}
class Engine {
private FuelPump fuelPump;
public void refuel() {
fuelPump.pump(); // Engine tells FuelPump
}
}
class FuelPump {
public void pump() { }
}
// Client code
car.refuel(); // Simple and decoupled
μ€μ μμ ¶
μμ ν SOLID μμ (JavaScript)¶
// S: Single Responsibility
class Product {
constructor(name, price) {
this.name = name;
this.price = price;
}
}
class ShoppingCart {
constructor() {
this.items = [];
}
addItem(product, quantity) {
this.items.push({ product, quantity });
}
removeItem(productName) {
this.items = this.items.filter(item => item.product.name !== productName);
}
getItems() {
return this.items;
}
}
// O: Open/Closed - discount strategies
class DiscountStrategy {
calculate(total) {
return total;
}
}
class NoDiscount extends DiscountStrategy {
calculate(total) {
return total;
}
}
class PercentageDiscount extends DiscountStrategy {
constructor(percentage) {
super();
this.percentage = percentage;
}
calculate(total) {
return total * (1 - this.percentage / 100);
}
}
class FixedDiscount extends DiscountStrategy {
constructor(amount) {
super();
this.amount = amount;
}
calculate(total) {
return Math.max(0, total - this.amount);
}
}
// D: Dependency Inversion
class OrderService {
constructor(paymentProcessor, discountStrategy) {
this.paymentProcessor = paymentProcessor; // Inject dependency
this.discountStrategy = discountStrategy;
}
checkout(cart) {
const total = cart.getItems().reduce((sum, item) =>
sum + item.product.price * item.quantity, 0);
const discounted = this.discountStrategy.calculate(total);
return this.paymentProcessor.process(discounted);
}
}
// Usage
const cart = new ShoppingCart();
cart.addItem(new Product("Laptop", 1000), 1);
cart.addItem(new Product("Mouse", 25), 2);
const discount = new PercentageDiscount(10);
const payment = new CreditCardProcessor();
const orderService = new OrderService(payment, discount);
orderService.checkout(cart);
μμ½¶
λ€ κ°μ§ κΈ°λ₯κ³Ό SOLID μμΉμ ν¨κ» μλν©λλ€:
| μμΉ | λ°©μ§νλ κ² | μ£Όμ μ΄μ |
|---|---|---|
| μΊ‘μν(Encapsulation) | λ°μ΄ν° μμ | λ°μ΄ν° λ¬΄κ²°μ± |
| μΆμν(Abstraction) | λΆνμν 볡μ‘μ± | λ¨μμ± |
| μμ(Inheritance) | μ½λ μ€λ³΅ | μ¬μ¬μ©μ± |
| λ€νμ±(Polymorphism) | κ²½μ§λ μ½λ | μ μ°μ± |
| SRP | μ ν΄λμ€(God classes) | μ μ§λ³΄μμ± |
| OCP | μμ νκΈ | μμ μ± |
| LSP | κΉ¨μ§ κ³μΈ΅ ꡬ쑰 | μ νμ± |
| ISP | λΉλν μΈν°νμ΄μ€ | κ²°ν©λ κ°μ |
| DIP | κ°ν κ²°ν© | ν μ€νΈ μ©μ΄μ± |
μ°μ΅ λ¬Έμ ¶
μ°μ΅ λ¬Έμ 1: μλ° μ¬ν μλ³¶
μ΄ μ½λλ₯Ό κ²ν νκ³ μ΄λ€ SOLID μμΉμ΄ μλ°λμλμ§ μλ³νμΈμ:
class EmailService:
def __init__(self):
self.smtp_server = "smtp.gmail.com"
self.port = 587
def send_email(self, recipient, subject, body):
# Connect to SMTP
# Send email
pass
def save_user(self, user):
# Save to database
pass
def generate_invoice(self, order):
# Generate PDF invoice
pass
def calculate_tax(self, amount, country):
if country == "US":
return amount * 0.07
elif country == "UK":
return amount * 0.20
elif country == "DE":
return amount * 0.19
# ... more countries
μ°μ΅ λ¬Έμ 2: μ»΄ν¬μ§μ μΌλ‘ 리ν©ν λ§¶
μμ κΈ°λ° μ€κ³λ₯Ό μ»΄ν¬μ§μ μ μ¬μ©νλλ‘ λ¦¬ν©ν λ§νμΈμ:
class Employee {
protected String name;
protected double salary;
public void work() { }
public void attendMeeting() { }
}
class Manager extends Employee {
public void managePeople() { }
}
class Developer extends Employee {
public void writeCode() { }
}
class ManagerDeveloper extends ??? { // Diamond problem!
// Needs both managePeople() and writeCode()
}
μ°μ΅ λ¬Έμ 3: 리μ€μ½ν μΉν μμΉ μ μ©¶
μ΄ LSP μλ°μ μμ νμΈμ:
class Bird {
public:
virtual void fly() {
std::cout << "Flying\n";
}
};
class Ostrich : public Bird {
public:
void fly() override {
throw std::logic_error("Ostriches can't fly!");
}
};
void makeBirdFly(Bird* bird) {
bird->fly(); // May throw exception!
}
μ°μ΅ λ¬Έμ 4: SOLID μ€κ³ ꡬν¶
λ€μ μꡬμ¬νμ λ§μ‘±νλ μλ¦Ό μμ€ν μ μ€κ³νμΈμ: - μ΄λ©μΌ, SMS, νΈμ μλ¦Ό μ§μ - μ°μ μμλ³ μλ¦Ό νν°λ§ νμ© - μλ‘μ΄ μλ¦Ό μ νμΌλ‘ μ½κ² νμ₯ κ°λ₯ - λͺ¨λ SOLID μμΉ μ€μ
μ°μ΅ λ¬Έμ 5: μ½λ 리뷰¶
μ½λλ² μ΄μ€(μμ μ κ² λλ μ€νμμ€)λ₯Ό κ²ν νκ³ λ€μμ μλ³νμΈμ: 1. μΊ‘μν μλ° 1κ° 2. κ°μ κ°λ₯ν μΆμν 1κ° 3. λΆμ μ ν μμ μ¬μ© 1κ° 4. λ€νμ±μ΄ λμμ΄ λ κ³³ 1κ° 5. SOLID μλ° μ΅μ 3κ°
μ΄μ : 04_Programming_Paradigms.md λ€μ: 06_Functional_Programming.md