객체지향 프로그래밍이란? 예시 상황과 예제 코드로 알아보자

조유정·2023년 10월 31일
0

인프런 김영한 강의를 들으면서 앞서 공부했던 내용이지만
코드를 짤 때마다 어떻게 해야할지 고민이 많아지는 부분이다. 🥲🥲🥲

예시 상황과 예제 코드로 개념을 굳혀보자!

💡 SOLID
  1. 단일 책임 원칙 (SRP, Single Responsibility Principle)
  2. 개방 폐쇄 원칙 (OCP, Open Close Principle)
  3. 리스코프 치환 원칙 (LSP, Liskov Substitution Principle)
  4. 인터페이스 분리 원칙 (ISP, Interface Segregation Principle)
  5. 의존성 역전 원칙 (DIP, Dependency Inversion Principle)

SRP (Single Responsibility Principle) - 단일 책임 원칙

"어떤 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 한다" - 로버트 C. 마틴

한 클래스는 하나의 책임만 가져야 한다. 하나의 클래스가 여러 책임을 가지게 되면, 클래스를 수정할 때 다른 책임에 영향을 끼치게 되고, 코드의 유지보수가 어려워집니다.

[예시 상황]

SRP

[예제 코드]

// SRP (Single Responsibility Principle)
class Car {
    public void start() {
        // ...
    }

    public void stop() {
        // ...
    }
}

OCP (Open Closed Principle) - 개방 폐쇄 원칙

"소프트웨어 엔티티(클래스, 모듈, 함수 등)는 확장에 대해서는 열려 있어야 하지만 변경에 대해서는 닫혀 있어야 한다." - 로버트 C. 마틴

확장에는 열려있고, 수정에는 닫혀 있어야 한다. 새로운 요구사항이 생겨도 기존의 코드는 수정하지 않고, 새로운 코드를 추가하여 변경되는 부분을 대응해야 합니다.

[예시 상황]

OCP1

OCP2

[예제 코드]

// OCP (Open-Closed Principle)
interface Shape {
    double getArea();
}

class Rectangle implements Shape {
    private double width;
    private double height;

    public double getArea() {
        return width * height;
    }
}

class Circle implements Shape {
    private double radius;

    public double getArea() {
        return Math.PI * radius * radius;
    }
}

LSP (Liskov Substitution Principle) - 리스코프 치환 원칙

"서브 타입은 언제나 자신의 기반 타입(base type)으로 교체할 수 있어야 한다." - 로버트 C. 마틴

상속은 조직도나 계층도가 아닌 분류도가 되어야 한다.

  • 하위 클래스 is a kind of 상위 클래스 : 하위 분류는 상위 분류의 한 종류이다.
  • 구현 클래스 is able to 인터페이스 : 구현 분류는 인터페이스 할 수 있어야 한다.

자식 클래스는 부모 클래스에서 가능한 행위를 수행할 수 있어야 한다. 즉, 상속 관계에서는 자식 클래스가 부모 클래스의 기능을 확장할 수 있어야 합니다.

[예시 상황]

LSP

[예제 코드]

// LSP (Liskov Substitution Principle)
interface Bird {
    void fly();
}

class Duck implements Bird {
    public void fly() {
        // ...
    }
}

class Ostrich implements Bird {
    public void fly() {
        throw new UnsupportedOperationException();
    }
}

ISP (Interface Segregation Principle) - 인터페이스 분리 원칙

"클라이언트는 자신이 사용하지 않는 메서드에 의존 관계를 맺으면 안 된다." - 로버트 C. 마틴

클라이언트는 자신이 사용하지 않는 메소드에 의존하도록 강요되어서는 안 됩니다. 인터페이스를 작은 단위로 분리하면, 클라이언트가 자신이 사용하는 메소드만 호출할 수 있습니다.

[예시 상황]

ISP

[예제 코드]

// ISP (Interface Segregation Principle)
interface Car {
    void drive();
}

interface Airplane {
    void fly();
}

class FlyingCar implements Car, Airplane {
    public void drive() {
        // ...
    }

    public void fly() {
        // ...
    }
}

DIP (Dependency Inversion Principle) - 의존 역전 원칙

"추상화된 것은 구체적인 것에 의존하면 안 된다. 구체적인 것이 추상화된 것에 의존해야 한다."

추상화에 의존해야지, 구체화에 의존하면 안 됩니다. 즉, 구체적인 클래스보다는 추상 클래스나 인터페이스에 의존해야 합니다.

[예시 상황]

OCP와 거의 비슷하다, 하나의 해결책을 찾으면 그 안에 여러 설계 원칙이 녹아있는 경우가 많다.

스노우 타이어가 무엇에도 의존하지 않는 클래스였는데, 추상적인 타이어 인터페이스에 의존하게 됐다.

의존의 방향이 역전된 것이다.

자신보다 변하기 쉬운 것에 의존하던 것을 추상화된 인터페이스나 상위 클래스를 두어 변하기 쉬운 것의 변화에 영향받지 않게 하는 것이 의존 역전 원칙이다.

[예제 코드]

// DIP (Dependency Inversion Principle)
interface Database {
    void save(String data);
}

class MySQL implements Database {
    public void save(String data) {
        // ...
    }
}

class User {
    private Database database;

    public User(Database database) {
        this.database = database;
    }

    public void saveData(String data) {
        database.save(data);
    }
}

참고

스프링 입문을 위한 자바 객체 지향의 원리와 이해

https://shoney.tistory.com/entry/SOLID-소스코드-예제-객체-지향-설계-5가지-원칙?category=1001322

https://p829911.tistory.com/24

profile
나는 아직 멍청하다

0개의 댓글