꾸준하게

누가 개발블로그에 이런 거까지 쓰냐에서 '누'를 담당하고 있습니다:)

Steadily

IT/[ GDSC ] 객체지향의 사실과 오해

[ 객체지향 사실과 오해 스터디 ] Day5_ 책임과 메시지

고구마개발자_인선 2024. 1. 7. 17:30

Day 4는 시험기간 이슈로 패스했다ㅎㅎ

Day 5부터 차곡차곡 정리해보자!

 

이번 챕터..쉽지 않다

단순히 책 내용 요약보다는

책에서 핵심이 되는 7가지의 내용을 실제 코드나 실제 상황 속 예시를 떠올리면서 정리해보도록 하겠다

사진은 뜬금없지만 대표사진이 필요하니까

조만간 가고싶은 스키장으로~

😎


1. 객체 지향 패러다임이 강력한 이유는 다형성을 이용해 협력을 유연하게 만들기 때문이다.

 

* 다형성(Polymorphism)은 상속 관계 내의 다른 클래스의 인스턴스들이 같은 멤버 함수 호출에 대해 각각 다르게 반응하도록 하는 기능, 이를 통해 코드의 재사용성과 유연성을 높일 수 있음.

 

* 예를 들어, 동물이라는 클래스에서 고양이, 개라는 클래스를 상속받았다고 가정해보자!

동물 클래스에는 '울다'라는 메소드가 있고, 고양이와 개 클래스에서 이 메소드를 오버라이드하여 각각 "야옹", "멍멍"이라는 소리를 내도록 하자

이렇게 하면 동물 객체를 통해 울다라는 메소드를 호출하면, 해당 객체가 고양이인지 개인지에 따라 다르게 반응한다!

 

* JAVA 예시 (동물)

abstract class Animal {
    abstract void sound();
}

class Cat extends Animal {
    void sound() {
        System.out.println("야옹");
    }
}

class Dog extends Animal {
    void sound() {
        System.out.println("멍멍");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myCat = new Cat(); // Cat 객체를 Animal 타입으로 선언
        Animal myDog = new Dog(); // Dog 객체를 Animal 타입으로 선언

        myCat.sound(); // "야옹"
        myDog.sound(); // "멍멍"
    }
}

 

 

 

 


2. 객체 지향의 강력함을 누리기 위한 시작은 책임을 자율적으로 만드는 것이다. 

- 객체가 책임을 자율적으로 수행하기 위해서는 객체에게 할당되는 책임이 자율적이어야한다. 
- 자율적인 책임의 특징은 객체가 어떻게 해야하는가가 아니라 무엇을 해야하는가를 설명한다는 것이다

 

* 객체 지향에서 중요한 개념 중 하나는 객체가 자신만의 책임을 가지고, 그 책임을 수행하는 방법을 스스로 결정하는 것! 이를 캡슐화라고 하며, 이를 통해 코드의 유연성과 재사용성을 높일 수 있음.

 

*예를 들어, 은행 계좌라는 객체가 있을 때, 이 객체가 자신의 잔액을 관리하는 책임을 가짐.

계좌에 입금하거나 출금하는 방법은 계좌 객체 스스로가 결정하고, 이에 대한 정보는 외부에 공개되지 않음.

 

* JAVA 예시 (은행계좌1)

class BankAccount {
    private int balance;

    BankAccount(int balance) {
        this.balance = balance;
    }

    // 입금 책임
    void deposit(int amount) {
        balance += amount;
    }

    // 출금 책임
    void withdraw(int amount) {
        if (balance < amount) {
            System.out.println("잔액이 부족합니다.");
            return;
        }
        balance -= amount;
    }

    // 잔액 확인 책임
    int getBalance() {
        return balance;
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount myAccount = new BankAccount(10000);

        myAccount.deposit(5000); // 입금
        System.out.println(myAccount.getBalance()); // "15000"

        myAccount.withdraw(3000); // 출금
        System.out.println(myAccount.getBalance()); // "12000"
    }
}

 

 

 

 


3. 객체의 책임과 인터페이스를 결정하는 것은 메시지로부터 시작된다.

 

* 객체 지향 프로그래밍에서 메시지는 객체들 사이에 정보를 전달하는 수단.

 

* 객체가 수신한 메시지를 통해 1) 어떤 행동을 해야 할지 2) 객체의 책임과 인터페이스를 결정하는 역할을 함.


* 예를 들어, '은행 계좌' 객체에 '입금'이라는 메시지를 보냈다면, '은행 계좌' 객체는 입금 책임을 수행하게 됨.

 

*JAVA 예시 (은행계좌2)

class BankAccount {
    private int balance;

    BankAccount(int balance) {
        this.balance = balance;
    }

//위 예시와 달라진 부분은 함수들을 책임으로 보는가, 특정 메시지를 처리하는 메소드로 보는가임
    // 입금 메시지를 처리하는 메소드
    void deposit(int amount) {
        balance += amount;
    }

    // 출금 메시지를 처리하는 메소드
    void withdraw(int amount) {
        if (balance < amount) {
            System.out.println("잔액이 부족합니다.");
            return;
        }
        balance -= amount;
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount myAccount = new BankAccount(10000);

        myAccount.deposit(5000); // 입금 메시지 전송
        myAccount.withdraw(3000); // 출금 메시지 전송
    }
}

 

 

 

 

 

 


4. 의도는 메시징이다.

- 훌륭하고 성장 가능한 시스템을 만들기 위한 핵심은 모듈 내부의 속성과 행동이 어떤가보다는 모듈이 어떻게 커뮤니케이션 하는가에 달려 있다 - 엘런 케이

 

* 위 문장들은 객체들이 서로 메시지를 주고받아서 동작하는 것을 강조함

 

* JAVA예시 (음료주문)

class Customer {
    void order(Beverage beverage) {
        beverage.prepare();
    }
}

abstract class Beverage {
    abstract void prepare();
}

class Coffee extends Beverage {
    void prepare() {
        System.out.println("커피를 준비 중입니다...");
    }
}

class Tea extends Beverage {
    void prepare() {
        System.out.println("차를 준비 중입니다...");
    }
}

public class Main {
    public static void main(String[] args) {
        Customer customer = new Customer();
        Beverage myCoffee = new Coffee();
        Beverage myTea = new Tea();

        customer.order(myCoffee); // 커피 주문
        customer.order(myTea); // 차 주문
    }
}

Customer 객체는 order 메서드를 통해 Beverage 객체에게 '음료 준비'라는 메시지를 보냄. 이를 통해 Beverage 객체는 각자의 방식으로 음료를 준비함.

이렇게 객체들이 메시지를 통해 커뮤니케이션하고, 각자의 역할을 수행하는 것이 중요함!

 

 

 


5. 객체지향의 강력함은 클래스가 아니라 객체들이 주고받는 메시지로부터 나온다.

- 메시지를 수신받은 객체는 자신이 수행할 수 있는 메시지인지 확인을 한 후에, 메시지를 처리할 수 있다. 즉, 메시지의 개념은 책임의 개념과 연결된다.
- 메시지는 객체로 하여금 자신의 책임, 즉 행동을 수행하게 만드는 유일한 방법이다.
- 메시지는 어떻게 수행될 것인지는 명시하지 않는다. 

- 단지 오퍼레이션을 통해 무엇이 실행되기를 바라는지만 명시하며, 어떤 메서드를 선택할 것인지는 자율적으로 정한다.

 

 

 

 


💥양이 많은 관계로 중간 정리💥

1) 메시지
- 객체들이 서로 협력하기 위해 사용할 수 있는 유일한 의사 소통 수단이다.
- 객체가 메시지를 수신할 수 있다는 것은 객체가 책임을 수행할 수 있다는 것을 의미한다.
- 메시지를 중심으로 설계된 구조는 유연하고 확장 가능하며 재사용 가능하며 자율적인 책임은 그대로 따라온다.

2) 자율적인 책임
- '어떻게 해야하는가'가 아니라 '무엇을 해야하는가'를 설명한다는 것이다.
- 메시지 -> 책임 -> 협력 관계
- 추상화된 메세지는 자율적인 책임을 가진 객체를 만들고, 자율적인 객체는 유연하고 단순한 협력을 만든다.

3) 응집도 : 모듈 안에 많은 기능이 얼마나 집중되어 있는지, 많은 기능을 책임지고 있으면 응집도가 낮아진다.
4) 결합도 : 서로 다른 모듈 간에 얼마나 의존하고 있는지, 결합도가 높으면 객체의 자율성이 낮아진다.

5) 다형성
- 하나의 메시지를 수신하는 수신자의 종류들이 서로 대체 가능하다.
- 다형성을 만족시킨다는 것은 객체들이 동일한 책임을 공유한다는 것을 의미한다.

 


 


6. 객체 설계의 핵심은 객체를 외부에 공개되는 인터페이스와 

내부에 감춰지는 구현인 두 개의 분리된 요소로 설계하는 것이다.

 

* 위의 문장은 '캡슐화'를 의미하는 것! 

 

* 캡슐화는 객체의 내부 상태를 외부에서 직접 접근하지 못하도록 숨기는 것을 의미함. 외부에서 객체의 상태를 변경하거나 조회하려면 객체가 제공하는 메소드를 통해야 함

 

* 이를 통해 객체의 내부 구현이 외부에 노출되지 않으므로, 내부 구현을 변경하더라도 외부에 영향을 주지 않고, 코드의 재사용성과 유연성 향상

 

* JAVA예시 (자동차)

class Car {
    private int speed; // 내부에 감춰진 구현

    Car() {
        this.speed = 0;
    }

    // 외부에 공개된 인터페이스
    void accelerate() {
        speed += 10;
    }

    // 외부에 공개된 인터페이스
    void brake() {
        if (speed < 10) {
            speed = 0;
        } else {
            speed -= 10;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Car myCar = new Car();

        myCar.accelerate(); // 가속
        myCar.brake(); // 제동
    }
}

 

Car 객체는 speed라는 내부 상태를 가지고 있으며, 이는 private 키워드로 외부에서 접근할 수 없게 되어 있음.

accelerate와 brake 메소드는 Car 객체의 외부 인터페이스로, 외부에서 Car 객체와 상호작용할 수 있는 유일한 방법!

 

 

 

 

 


 

7. 책임의 자율성이 협력의 품질을 결정한다.

객체지향 패러다임이 강력한 이유는 다형성을 이용해 협력을 유연하게 만들 수 있기 때문이라는 점!

 

* JAVA예시 (피자와 파스타)

abstract class Food { // 추상 클래스
    abstract void prepare(); // 추상 메소드
}

class Pizza extends Food {
    void prepare() { // 다형성 구현
        System.out.println("피자를 준비합니다. 반죽을 만들고, 소스와 토핑을 올리고, 오븐에서 구웁니다.");
    }
}

class Pasta extends Food {
    void prepare() { // 다형성 구현
        System.out.println("파스타를 준비합니다. 물에서 파스타를 삶고, 소스를 만들어 파스타와 잘 섞습니다.");
    }
}

public class Main {
    public static void main(String[] args) {
        Food myPizza = new Pizza();
        Food myPasta = new Pasta();

        myPizza.prepare(); // 피자 준비
        myPasta.prepare(); // 파스타 준비
    }
}

 Food는 추상 클래스로, prepare라는 추상 메소드를 가지고 있음.

 Pizza와 Pasta 클래스는 Food 클래스를 상속받아 prepare 메소드를 각각 다르게 구현. 이렇게 하면 Food 클래스의 참조 변수로 Pizza와 Pasta 객체를 다룰 수 있으며, prepare 메소드를 호출하면 각각 다른 행동을 보일 수 있음

이게 다형성임!!

 

 


끝!!

오늘 양이 많은데,,,다른 스터디원분들이 내가 놓친 부분들을 잘 채워주었을 것이라고 생각한다

루삥빵😁

반응형