객체지향프로그래밍

이영주·2021년 5월 8일
0

객체지향프로그래밍

  1. 프로그램의 어떤 객체들이 필요할지 정하기
  2. 객체들의 속성과 행동을 정하기
  3. 서로 어떻게 소통할지 정하기

객체지향 프로그램을 이해하기 위한 개념들

1. 추상화(Abstraction)
-변수나 함수를 작성하는것도 추상화와 같다. 변수의 값을 한번 설정하면 이후 값을 알지 못해도 변수를 사용하면 되기 때문이다. 마찬가지로 클래스도 추상화이다. 클래스를 사용하기 위한 최소한의 정보만 알면 사용할 수 있다.
-변수나 함수, 클래스 등 정의할 때 이름을 잘 짓는것과 독스트링을 통해 문서화를 하면 시간이 지난 후 본인이 다시 사용할 때나 동료 개발자들이 사용하기 편하다.

2. 캡슐화(Encapsulation)
-객체의 구현 내용에 대한 외부로부터의 직접적인 액세스를 차단하는것이다. 변수나 메소드의 이름 앞에 언더바 두개를 붙이면 클래스 밖에서 접근이 불가능해진다. 변수의 접근할 수 있는 메소드를 따로 만들어서 사용한다.
-변수의 값을 읽는 성격의 메소드를 getter 메소드, 변수의 값을 설정하는 성격의 메소드는 setter 메소드라고 한다.
-파이썬에서는 언어 자체에서 캡슐화를 지원하지 않는다. 개발자들은 캡슐화에 대해 어떤 변수나 메소드에 함부로 접근하지 말라는 표시로 언더바 한개를 쓰고 약속처럼 지킨다.
-메소드 위에 @property 라고 쓰면 그 메소드를 변수에 대한 getter 메소드로 만든다.

3. 상속(Inheritance)
-상속을 이용하면 반복되는 내용을 한 번만 써도 된다.
-부모클래스에서 물려받은 내용을 자식클래스가 자신에 맞게 변경하는 것을 오버라이딩이라고 한다.
-다중상속은 상속받는 순서에 따라 mro가 바뀌기 때문에 메소드 호출 순서를 신경써야하는 문제가 생길 수 있어서 java에서는 지원하지 않는다. 파이썬에서 다중상속을 한다면 부모클래스들이 같은 메소드를 갖지 않도록 하거나 같은 메소드 이름이 있다면 자식 클래스에서 아예 오버라이딩 해두는게 좋다.

4. 다형성(Polymorphism)
-하나의 변수가 서로 다른 클래스에서 인스턴스를 가리킬 수 있는 성질을 다형성이라고 한다.
-상속이 없는 다형성을 가지면 해당 인스턴스를 일일이 확인해야하는 문제가 생길 수 있어서 상속을 통해 문제를 해결한다.
-일반상속을 받으면 자식클래스가 오버라이딩을 하지 않았는데도 추가되는 경우가 생겨 문제가 생길 수 있다. 메소드를 강제로 오버라이딩 하게 하려면 추상클래스를 사용하면 된다. 추상클래스에서 추상메소드는 자식클래스가 반드시 오버라이딩 해야하는 메소드다. 추상메소드는 type hinting을 해주는게 좋다.
-추상클래스에도 @abstractmethod를 쓰지 않는 일반메소드를 사용할 수 있다.
-추상클래스 다중상속은 일반적으로 많이 사용한다. 다중 상속받는 부모 추상클래스들이 추상메소드로만 이루어져있으면 아무 문제없이 다중상속을 받을 수 있다. 그러나 이름이 겹치는 일반메소드가 있으면 일반클래스를 다중 상속 받을때와 동일한 문제가 생길 수 있다.

어떻게 유지보수하기 쉬운 코드를 만들 수 있는지를 알아야 한다.
대표적인 객체 설계의 원칙 5가지

1. 단일 책임 원칙 (Single Responsibility Principle)
-모든 클래스는 단 한가지의 책임만을 갖고, 클래스 안에 정의되어 있는 모든 기능은 이 하나의 책임을 수행하는데 집중되어 있어야 한다. 간단히 말해 하나의 클래스로 너무 많은 일을 하지 말고 딱 한가지 책임만 수행할 것.
-같이 수정해야될 것들은 묶고, 따로 수정해야될 것들은 분리하는것
-프로그램의 크기가 커질수록 단일 책임 원칙을 지키지 않은 것 때문에 코드를 수정하기가 점점 힘들어지는걸 느낄 수 있을 것이다.
-중요한것은 코드를 작성할 때, 내가 단일 책임 원칙을 지키고 있는지(클래스가 너무 많은 책임을 갖고있는건 아닌지, 하나의 클래스 안에 분리할 수 있을 것 같은 변수와 메소드들이 있는지) 신경쓰는 것

2. 개방 폐쇄 원칙 (Open-closed Principle)
-클래스는 확장에 열려있어야 하며, 수정에는 닫혀있어야 한다.
-추상클래스를 이용해 기존의 클래스의 코드를 수정하지 않고도 기능을 확장할 수 있다.

3. 리스코프 치환 원칙 (Liskov Substitution Principle)
-부모클래스의 인스턴스를 사용하는 위치에 자식클래스의 인스턴스를 대신 사용했을 때 코드가 원래 의도대로 작동해야 한다. 2가지 조건이 만족되면 가능하다.
-첫째는 형식적 측면에서 자식클래스가 오버라이딩하는 변수와 메소드가 부모클래스에 있는 형식과 일치해야 한다. 변수의 경우에는 타입, 메소드의 경우에는 파라미터와 리턴값의 타입 및 개수를 말한다. 이런것들을 지키지 않으면 프로그램 실행 시 에러가 발생한다.
-둘째는 내용적인 측면에서 자식클래스가 부모클래스의 메소드에 담긴 의도, 그러니까 부모클래스의 행동규약을 위반하지 않는것이다. 프로그램을 실행해도 에러가 나지는 않지만 예상했던 결과가 아닌 전혀 다른 결과를 프로그램이 내놓게 된다.

4. 인터페이스 분리 원칙 (Interface Segregation Principle)
-지나치게 많은 추상 메소드를 가진 거대한 인터페이스 하나를, 관련된 추상 메소드들만 모여있도록 작은 크기의 인터페이스로 분리하라는 것. 이유는 지나치게 큰 인터페이스는 그걸 상속하는 클래스가 자신에게 필요하지도 않은 메소드를 굳이 오버라이딩하도록 만들기 때문이다.
-인터페이스가 서로 관련성이 높은, 적절한 개수의 추상 메소드들을 포함하게 될 때 그걸 역할 인터페이스(role interface)라고 한다.
-큰 인터페이스 하나가 있는 것보다는 작은 역할 인터페이스 여러 개가 있으면 각 클래스가 본인에 해당하는 인터페이스만 적절히 상속받는다. 그럼 각 클래스가 어떤 기능을 갖는지 더 세밀하게 파악할 수 있게 해준다는 장점을 가진다.
-중요한것은 관련있는 기능끼리 한 인터페이스에 모으고, 한 인터페이스가 지나치게 커지지 않도록 하겠다는 생각을 갖고 설계하는 것이다.

5. 의존 관계 역전 원칙 (Dependency Inversion Principle)
-상위모듈은 하위모듈의 구현 내용에 의존하면 안된다. 상위모듈과 하뮈모듈 모두 추상화된 내용에 의존해야 한다.
-이유는 상위모듈이 하위모듈을 사용할 때 직접 인스턴스를 가져다쓰면 하위모듈의 구체적인 내용에 상위모듈이 의존하게 되어, 하위모듈의 변화가 있을 때마다 상위모듈의 코드까지 함께 바꿔줘야 하기 때문이다.
-해결책은 추상클래스로 상위모듈과 하위모듈 사이에 추상화레이어를 만드는것이다. 이것으로 추상클래스의 자식클래스의 인스턴스를 상위모듈이 사용할 때 그 하위모듈을 사용하는 코드를 작성해두면 되고 하위모듈은 추상클래스의 추상메소드를 오버라이딩만 하면 된다. 그러면 새로운 하위모듈이 생겨도 기존 코드를 수정하지 않고 새 하위모듈을 자유롭게 가져다쓸 수 있으므로 코드를 유지보수하기 편해진다. 개방폐쇄원칙을 지키는 하나의 방법이다.

0개의 댓글