5 minute read

객체지향

“현실에 존재하는 사물을 있는 그대로 모델링”

  • C언어 등과 같은 절차지향 언어는 프로그램 복잡도가 증가하면서 유지보수 및 개발 기간 등 다양한 부분에서 비효율 발생
  • 위와 같은 어려움을 해결하기 위한 효과적인 개발 방식을 채택하기 위해 등장
  • 객체 지향의 특징 : 추상화, 상속, 은닉, 다형성, 캡슐화, 재사용, 인터페이스 등

🌷 객체 지향의 4대 특성 : 캡슐화, 상속, 다형성, 추상화

🌻 추상화 : 객체에 필요한 데이터 및 메서드에 대한 밑그림을 그리는 것

  • 개념도를 설계한다고 생각
  • 다형성, 상속과 비교하였을 때, 탱크나 세단 등이 하나의 Unit이 되고 그 기능으로 공통적인 부분들로써 move가 포함될 수 있겠다! 라고 대략적인 틀을 정의하는 것을 의미

🌻 상속 : 객체의 데이터 및 메서드를 자식클래스에 물려주는 것

  • 자바는 다중상속 시 발생가능한 충돌(메서드명이 같은데 어떤 클래스로부터 물려받은지 구분이 안되는 경우 등)을 막기 위해서 다중상속이 지원되지 않음
  • 하위로 내려갈수록, 자손클래스가 될 수록 보다 구체화됨(속성과 메서드가 더욱 풍부해짐)
  • 장점
  • 프로그램 구조에 대한 이해도 향상 : 최상위 클래스의 구조를 보고 하위 클래스의 동작 이해 가능(예: move메서드를 통해서 움직임을 예측)
  • 재사용성 향상 : 필요한 속성이나 메서드를 물려받고, 재정의할 수 있음
  • 확장성 향상 : 일관된 형태로 객체를 추가하고, 부가적인 부분만 별도 정의할 수 있음
  • 유지보수성 향상 : 상속을 통해 물려받은 속성과 메서드는 같은 부모 클래스를 물려받은 클래스에서도 동일한 형태로 물려받아 작성 가능

🌻 은닉 : 객체의 데이터를 외부에서 무작위로 접근하지 못하도록 막아주는 것

🌻 다형성 :

  • 한 객체가 다른 여러 객체로 재구성될 수 있는 것
  • 오버라이딩: 메서드의 이름과 파라미터 갯수와 타입 모두 일치하는 메서드로, 내용을 재정의
  • 오버로딩 : 메서드의 이름은 같으나, 파라미터의 갯수 혹은 타입이 다른 메서드
  • 같은 부모 클래스 혹은 인터페이스를 상속받는 자식클래스들 간 공통적인 부분이 존재하는 경우, 이를 묶을 경우에도 사용할 수 있음

ex) List list = new ArrayList<>(): List list = new LinkedList<>();

===================================== 만약, Unit이라는 클래스의 자식클래스로 탱크, 세단 등이 있는 상황에서 private void unitMove(Unit unit){ unit.move();//캡슐화-내부메서드를 호출 } 위와 같이 부모클래스를 이용한 메서드를 기입해둔다면 자식클래스에서도 해당 메서드인 unitMove를 일괄적용받을 수 있다! 이 또한 위에서 리스트의 예와 마찬가지로 다형성이 적용되어

Unit unit = new 탱크(); 처럼 사용될 수 있기 때문이다!

🌻 캡슐화 : 객체에 필요한 데이터 및 메서드를 객체에 그룹화해주는 것

  • 데이터를 메서드를 통해서 우회하여 접근할 수 있도록 하는 것
  • method 설계

-속성이 선언되었지만 상태를 변경할 수 있는 메서드가 없다면 잘못된 것!!

-실물 객체가 가진 기능을 모두 제공해야 함

-각각의 메서드는 서로 관련성이 있어야 함

-객체 안의 메서드는 다른 객체를 전달받아서 처리하면 안된다!

단, 다른 객체가 필요한 경우에는 그 객체를 이용하지 않고, 그 객체의 getter 메서드를 이용해서 값 자체를 매개변수로 전달해주어야 한다!

  • getter/setter
  • CRUD method
  • 비즈니스 로직 메서드
  • 객체의 생명 주기 처리 메서드

-예: destroy(), disconnect() 등 소멸과 관련된 메서드

  • 객체의 영구성 관리 메서드(유효성 속성에 대한 변경이 필요한 경우 private으로 막은 후 내부의 다른 메서드로 사용하도록)

-캡슐화의 장점

  • 재사용성 향상 - 객체의 모듈성과 응집도가 높아지기 때문에 전역변수의 개념적 영향이 없음[전체 프로그램에 영향x]
  • 유지보수의 효율성 향상
  • 추상화가 재공됨 - 실제 메서드가 어떻게 동작하는지 외부에서 이해할 필요x
  • 무결성 보장 - 필드값에 대한 접근을 getter setter를 제외한 다른 메서드들은 파라미터로 전달받아 실행하게 함으로써 객체의 값에 대한 유효성을 가질 수 있게 됨

🌷 C++과 자바의 차이점

  • 시스템 레벨 접근
  • 메모리 직접 할당 및 해제
  • 포인터

등 복잡한 개발 방식을 자바에서는 추구하고 이지 않으며

어떤 운영체제에서도 자바 가상 머신 JVM만 있으면 독립적으로 실행가능하도록 설계되어 있기 때문에 여러 플랫폼과의 호환성이 우수!

🌷 객체의 3가지 요소

  • 아래와 같은 요소를 지키지 않은 경우를 “불완전 객체”라 명명
  1. 상태 유지(객체의 상태)
    • 객체는 상태 정보를 변수를 이용하여 속성으로써 저장하고 유지해야 함
    • 이러한 속성은 그 값의 변경에 따라서 객체의 상태가 변경될 수 있어야 함
  2. 기능 제공(객체의 책임)
  • 메서드로 인해 제공됨
  • 캡슐화와 관련
  • 외부로부터 직접 속성에 접근하지 않고 메서드로 속성을 우회접근할 수 있도록 제공되어야 함
  1. 고유 식별자 제공(객체의 유일성)
  • 각각의 객체는 고유한 식별자를 지녀야 함( DB에서의 기본키 제약조건 혹은 UNIQUE 제약조건 같은 것)

🌷 물리 객체와 개념 객체

  1. 물리객체 : 실제로 존재하는 사물을 정의한 객체
  2. 개념객체 : 웹 시스템에서 Service에 해당됨. 비즈니스 로직을 처리하는 부분을 의미
    • 실질적으로 대부분의 설계는 이러한 개념객체를 이용한 처리 부분이 많기 대문에 속성 및 오퍼레이션(메서드)를 잘 정의해야할 필요 존재!
    • 예: 사용자의 action에 따라 계좌 잔고 속성을 변경하는 입/출금 처리, 계정만료

🌺 객체 지향 설계 5원칙 SOLID

개념 1. 응집도와 결합도

  • 좋은 SW 설계 ⬅️ 결합도(coupling) ⬇️ & 응집도(cohesion) ⬆️

*결합도

  • 모듈(클래스)간 상호 의존 정도를 나타내는 정도
  • 결합도가 낮으면 모듈간 상호의존성 ⬇️ ➡️ 객체의 재사용 및 유지보수 유리
  • 결합도가 높으면 , 즉 절차지향 언어입장에서는, A-B-C 로 연결되어 A를 수정하면 B,C도 수정해야 함!

*응집도

  • 하나의 모듈 내부에 존재하는 구성요소들의 기능적 관련성
  • 응집도가 높은 모듈은 하나의 책임에 집중하고 독립성이 높아져서 재사용 및 유지보수가 용이
    1. S SRP “Single Responsibility Principle” 단일 책임 원칙
  • 어떤 클래스를 변경해야 하는 이유는 단 한가지뿐이어야 함!
  • 각 모듈은 그 모듈의 기능에 집중할 수 있도록 분리해두도록 하는 원칙!(아래그림처럼) ▶️ 응집도가 높아짐
  • 새로운 기능 추가 혹은 기능 수정시 유지보수 비용 부담이 줄어듦
  • 동시에, 상속과 다형성을 적용한다면 기능의 변경 등의 상황의 영향도 줄어듦
public class Unit{
  private int    hp;
  private int    speed;
//...생략
  public void move(){~~~}
  public void attack(){~~~}
}

public class 탱크 extends Unit{
  @Override
  public void move(){
    this.speed+=10;
  }
  @Override
  public void attack(){
    this.hp-=10;
  }
}
 탱크는 탱크의 기능만 수행할  있게 됨으로써 전반적인 프로그램에 
대한 영향이 줄어듦!

https://github.com/hy6219/TIL-Today-I-Learned-/blob/main/Spring/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%20solid%EC%9B%90%EC%B9%99-%EB%8B%A8%EC%9D%BC%EC%B1%85%EC%9E%84%EC%9B%90%EC%B9%99%20single%20responsibility%20principle.png?raw=true

SOLID 원칙-SRP(Single Responsibility Principle)

  1. O OCP “Open Closed Principle” 개방 폐쇄 원칙
  • 자신의 확장에는 열려있고, 주변의 변화에는 닫혀있어야 함
  • 상위 클래스나 인터페이스를 중간에 두게 되면, 내부적으로는 단 하나의 통로를 두고, 외부적으로는(자식클래스 방향으로 뻗어나가는 모습) 여러 통로를 두는 모습(해당 클래스나 인터페이스를 상속받는 다른 클래스까지 포함하여 전체적인 그림으로 보았을 때)을 보이게 된다. 이를 통해서 자기자신의 내부통로를 통한 확장에는 열려있고 그 외에는 닫혀있기 때문에 , 자기자신의 확장을 수행하게 된다!
  • 예) JDBC, MyBatis, Hibernate 등
  • 예) 입출력 스트림-보조스트림과 메인스트림 간 관계
  1. L LSP “Liskov Substitution Principle” 리스코프 치환 원칙
  • 서브타입은 언제나 자신의 상위(슈퍼)타입으로 교체할 수 있어야 한다!

https://github.com/hy6219/TIL-Today-I-Learned-/blob/main/Spring/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%20solid%EC%9B%90%EC%B9%99-%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84%EC%B9%98%ED%99%98%EC%9B%90%EC%B9%99%20liskov%20substitution%20principle%20LSP.png?raw=true

객체지향 SOLID 설계원칙- LSP Liskov Substitution Principle 리스코프 치환 원칙

먼저 위의 그림으로 이해해보자

왼쪽은 리스코프 치환원칙이 적용되지 않은 상태이고, 오른쪽은 리스코프 치환 원칙이 적용된 상태이다

왼쪽의 경우 소나타는 아반떼가 될 수 없고 그랜저도 아반떼가 될 수 없다

하지만 오른쪽의 경우, 정찰기는 공중유닛이자 비행기가 될 수 있고

수송기도 마찬가지다! 이러한 특징은 상속과 다형성을 생각하게 한다!

덧붙이자면, 부모의 기능을 자식클래스에 적용했을 때 전혀 이물감이 없는 상태를 일컬을수 있는 개념이라고 생각해도 무방하다! 아래의 블로그에서 해당 예시를 잘 보여주고 있다!

SOLID 원칙

  1. I ISP “Interface Segregation Principle” 인터페이스 분리 원칙
  • 클라이언트는 자신이 사용하지 않는 메서드에 의존관계를 맺으면 안된다!
  • 프로젝트 요구사항과 설계에 따라 SRP 혹은 ISP 원칙을 선택[SRP 개념과는 다르기 때문!- SRP는 기능에 집중할 수 있도록 지원]
  • 사용하지 않는 인터페이스, 즉 기능의 집합체는 관계를 맺으면 안된다는 것!
  • 자전거 내비게이션이 필요없는데 굳이 관계를 맺을 필요는 없음!
  1. D DIP “Dependency Inversion Principle” 의존 역전 원칙
  • 자신보다 변하기 쉬운것에 의존하지 말 것!
  • OCP에서 살펴본 바와 유사하다고 할 수 있는 형태로, 예를 들어서 사람은 계절에 따라 옷을 다르게 입을 수 있는데 이를 DIP를 통해 설계하면

https://github.com/hy6219/TIL-Today-I-Learned-/blob/main/Spring/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%20solid%EC%9B%90%EC%B9%99-dip%20depedency%20inversion%20principle.png?raw=true

객체지향 SOLID 설계-DIP Depedency Inversion Principle

옷은 계절에 따라 달라지는 데 만약 위와 같이 설계하지 않고

사람← 봄옷 사람← 여름옷과 같이 설계한다면 이는 DIP에 위배된다!

덧붙이자면, DIP에서는 변화하는 것 == 구체적인 것! 이라고 생각하면 된다!(https://dev-momo.tistory.com/entry/SOLID-원칙 참고!)

즉 위와 같이 설계한다면, 사람은 옷에 의존하게 되고, 봄 옷도 여름옷도 가을옷도, 겨울옷도 옷을 의존하게 되어 의존의 역전이 일어나게 된다. 즉, 옷이라는 인터페이스 혹은 상위 클래스를 둠으로써 사람은 덜 구체적인, 즉 변화하지 않는것과 관계를 맺게 된다!

Updated: