<객체 지향 프로그램>
상태는 형태를 통해서만 변경 받는다. (캡슐화) 데이터와 함수를 하나의 덩어리(객체)로 묶는 것. 상태를 직접적으로 변경하지 못한다.
캡슐화
정보 은닉이 목적 (private)
> 메소드의 책임을 하나씩 만드는 것.
(데이터와 해당 데이터를 조작하는 메서드를 하나의 단위로 묶는 것을 의미)
캡슐화 예시
package ex07; interface 행위{ void start(); } class 라면 implements 행위 { private void 물끓이기(){} private void 스프넣기(){} private void 면넣기(){} private void 계란넣기(){} @Override public void start() { //순서를 여기서 정해줌! start만 때리면 이 순서대로 나옴 물끓이기(); 스프넣기(); 면넣기(); 계란넣기(); } } public class ramenTest { public static void main(String[] args) { 라면 ra = new 라면(); ra.start(); //개발자 입장에서 보이는건 start 뿐이니까... } }
추상화
복잡한 시스템이나 개념을 단순화하고 중요한 요소에 집중하는 것
오브젝트를 추상화 해서 만든다. (상속해서 만든다.)
모두가 부모를 바라보게 만들면 수정할 게 없어서 프로그램 유지·보수에 엄청 편하다.
다형성
한 객체가 여러 가지 타입을 가질 수 있는 능력
동일한 코드가 다양한 객체에 대해 다양한 방식으로 동작할 수 있어서
코드의 유연성과 확장성을 높여준다.
상속
자식 클래스는 부모 클래스의 모든 속성과 동작을 물려받는다.
상속을 하려면 다형성을 꼭 지켜야함!
객체 지향은 ‘상태와 행위’ 모두 들고 있다.
유틸리티 클래스 = 행위만 들고 있는 것. 기능을 수행하는 것. 객체 지향 코드는 아니다.
[ 로버트 마틴의 SOLID ]
1. 단일 책임 원칙 (SRP)
클래스는 하나의 책임만 가져야한다는 말은, 메서드 하나만 가진다는게 아니다. 청소 / 회계 / 인사 처럼 나눠서, 청소가 잘못되면 청소 담당 메서드의 잘못. 금액이 잘못되면 회계 담당 메서드의 잘못. 이렇게 알기 쉽게 하려고 하는 것. 빗자루 쓸기, 청소기 돌리기. 이런 걸 가진다는게 아니다.
2. 개방-폐쇄 원칙 (OCP)
메서드 재정의해서 동적바인딩 해야 함! 새로운 코드를 만드는 건 OPEN, 기존 코드를 손대는건 CLOSE
3. 리스코프 치환 원칙 (LSP)
오브젝트 같은게 있으면 다운캐스팅 하고 쓰는 그런것... 디자인 패턴 같은걸 공부할 때, 제대로 이해할 수 있다. 지금은 X 서브타입(질럿)은 언제나 기반타입(프로토스)으로 교체할 수 있어야한다.
4. 의존관계 역전 원칙 (DIP) ✓
질럿을 보지말고 프로토스를 봐라 (프로토스에 의존해라)
5. 인터페이스 분리 원칙 (ISP)
인터페이스가 제약하는 행위를 들고 있을 수 있다. (ex. 엑셀, 브레이크 등등) 이런 걸 여러개 만들지 말고, 한 개만 만들라는 말 만약, 행위의 제약을 4개를 시켜야 한다면? 애가 4개를 잘 쓰다가, 이 인터페이스를 다른 클래스에서 사용할때, 2개만 사용하고 싶을 때가 있잖아? 이때 재사용이 안된다!
[ 인터페이스가 제약하는 행위를 2개 들고 있는 경우 ]
package ex17; interface Knife { //2개를 들고있다는게 중요 void kill(); void cook(); } class 백종원 implements Knife { //백종원은... cook만 하는데ㅠㅠ? @Override public void kill() { //kill 안써...ㅠ 이거 만들 필요 없잖아!! 이상한 짓 } @Override public void cook() { System.out.println("요리하다"); } } class 전사 implements Knife { @Override public void kill() { System.out.println("공격"); } @Override public void cook() { System.out.println("요리"); } } public class Hello { }
[ 이상한 짓 1 ]
package ex17; interface Knife { //2개를 들고있다는게 중요 void kill(); void cook(); } abstract class 요리사어댑터 implements Knife { //추상클래스라 추상메서드 가질 수 있잖어 오류 안남 //즉, 어댑터는 안쓰는걸 걸러낼 수 있다! //어댇터라는 애가 kill을 구현해버림 > 어댑터 패턴 @Override public void kill() { } } class 백종원 extends 요리사어댑터 { //요리사 어댑터를 상속받은 덕분에 백종원은 cook만 구현해도 됨! @Override public void cook() { System.out.println("요리하다"); } } class 전사 implements Knife { @Override public void kill() { System.out.println("공격"); } @Override public void cook() { System.out.println("요리"); } } public class Hello { }
[ 이상한 짓 2 ]
package ex17; interface Knife { //2개를 들고있다는게 중요 default void kill() { //인터페이스 메소드에 defualt를 하면 몸체를 만들 수 있다 (new 문법) //어댑터 패턴 안쓸려고 나옴 } void cook(); } class 백종원 implements Knife { //Knife에서 kill몸체를 구현했으니 cook만 구현하면 된다 @Override public void cook() { System.out.println("요리하다"); } } class 전사 implements Knife { @Override public void kill() { System.out.println("공격"); } @Override public void cook() { System.out.println("요리"); } } public class Hello { }
[ ISP를 지킨 코드 ]
저딴 이상한 짓 하지말고 ISP 를 지키기 위해 이렇게 써라!!
package ex17; interface CookAble { void cook(); } interface KnifeAble { void kill(); } class 백종원 implements CookAble { //Knife에서 kill몸체를 구현했으니 cook만 구현하면 된다 @Override public void cook() { System.out.println("요리하다"); } } class 전사 implements CookAble, KnifeAble { @Override public void kill() { System.out.println("공격"); } @Override public void cook() { System.out.println("요리"); } } public class Hello { }
Share article