본문 바로가기

자바

객체지향의 4대 특징

1.추상화
추상화란 핵심적으로 중요한 내용과 그렇지 않은 내용을 가려내는 것을 의미한다.
실생활에서 추상화를 설명할때  초기 지하철 지도를 예로 들면서 설명을 한다. 아래의 사진은 세계 최초의 지하철 지도다.
보고 바로 이해가 잘 안된다. 가독성이 떨어지고 불필요한 정보가 많다.
 
어떤 것이 불필요한 정보인지 일일이 설명하지는 않겠다. 여하튼 '추상화' 의 과정을 거치면 우리가 아는 오늘날의 원형에 가까운 지하철 지도가 등장한다.

 

훨씬 보기 편해진다.
 
개발에서 추상화는 공통적인 내용을 가려내는 것을 의미한다.
부모클래스를 둬서 자식클래스에서 중복되지 않는 메소드나 필드를 설정하는 것도 추상화중 하나다.
추상 클래스나 인터페이스를 사용해서 추상메소드를 사용하게끔 만드는 것도 추상화의 한갈래이다.
 
중복되는 내용의 메소드 이름만 정의해주면 메소드의 몸통(명확하게 해야하는 행위)은 개발자가 직접 구현해야 한다.
이를 통해서 중복되는 내용을 줄일 수 있다.
 
2.상속
부모클래스로부터 상속받은 메소드나 멤버변수를 물려받아서 사용할 수 있다.
부모클래스로부터 메소드를 상속받은뒤 재정의해서 사용하면 메소드를 "오버라이드" 한다고 표현하는데 이는 다형성의 한 형태이다.
 
3.캡슐화
객체의 정보를 외부에서 확인할 수 없게끔 숨기는 것이다.
접근제어자 private을 사용하면 된다.
 
객체는 캡슐화를 통해서 데이터를 외부로부터 은닉할 수 있다.
 
그런데 왜 은닉해야 하는 걸까? 오픈하면 안됨? 막말로 private 으로 멤버변수 설정해놓고 getter나 setter로 메번 설정해야 할 필요가 있음?
자바에서는 그럴수록 보일러 플레이트가 늘어나는 건데 왜 굳이 그런 리스크를 지면서 까지 은닉화를 해야함?
 
그 이유는 객체간의 결합도를 낮추기 때문이다.
아래 내가 직접 만든 예제를 보자.
 
치킨 클래스가 있다.
public class Chicken {

    private String type = "2호";
    public String getType() {
        return type;
    }
}
 
cooking() 메소드를 두개를 만들었다. 첫번째 메소드는 getter 메소드를 사용해서 치킨 객체를 갖고오고 두번째 메소드는 그냥 메소드 안에 치킨 객체를 생성해서 사용한 케이스다. 첫번째 케이스의 경우 Chicken 클래스의 내용이 바뀌면 Cooker의 메소드 내용을 고쳐야 할게 없다. 반면 두번째는 다 뜯어 고쳐야 한다.
public class Coocker {

    public void cooking(){
        Chicken chicken = new Chicken();
        if(chicken.getType().equals("2호")){
            System.out.println("고객님 양념통닭 나왔습니다 ㅎㅎ");
        }
        else{
            System.out.println("이런 치킨으로 나는 요리할 수 없어!");
        }
    }

    // 캡슐화를 하지 않고 사용하는 경우다. 치킨 클래스의 내용이 바뀌면 요리사 클래스의 내용도 전면 수정해야 한다. 이런 경우를 '결합도가 높다' 라고 표현한다.
    //가장 지양해야 하는 상황의 개발.
    public void cooking(Chicken chicken){
        // 실제로 쓰려고 하면 
        if(chicken.type.equals("2호")){
            System.out.println("고객님 양념통닭 나왔습니다 ㅎㅎ");
        }
        else{
            System.out.println("이런 치킨으로 나는 요리할 수 없어!");
        }
    }
}
이때 우리는 캡슐화를 활룡해서 객체의 자율성, 즉 하나의 객체가 해당 객체의 속성과 기능에 대한 독점적인 책임을 담당하도록 만들고, 이를 통해 객체 간의 결합도를 낮게 유지할 수 있다.
 
 
4.다형성
같은 이름의 메소드가 다양한 모양을 가질 수 있다는 말이다. 형 이 형상형 形 이다.
부모클래스로부터 메소드를 오버라이드 받아서 재정의 하는것도 이에 해당되고 오버로딩을 통해 메소드의 내용이 다르거나 매개변수를 서로 다르게 하는 것도 다형성의 한 종류이다.
 
다형성은 왜 필요한가?
다양한 상황에 맞춰서 원하는 형태의 메소드를 맞춰서 쓰라고 있는거다.
 
여기까지는 내가 말한 설명이고 출처의 내용에 따르면 다형성의 목적은 아래와 같다.
 
객체지향에서 다형성이란 한 타입의 참조변수를 통해 여러 타입의 객체를 참조할 수 있도록 만든 것을 의미한다. 좀 더 구체적으로 말하면, 상위 클래스 타입의 참조변수로 하위 클래스의 객체를 참조할 수 있도록 하는 것이다.
 
위의 말이 리스코프 치환원칙이랑 같은 말이다. (이미 리스코프 치환원칙을 정리하면서 봤던 내용이다.)
List tmp = new ArrayList<String>();
List 는 인터페이스이고 ArrayList는 List인터페이스를 구현한 구현체이다.
인터페이스 객체인 tmp안에 인터페이스의 구현체 ArrayList 를 넣는 것이다.
다형성의 원리가 적용되서 인터페이스 변수 tmp 안에 기존의 ArrayList 뿐만이 아니라 아래와 같은 코드들도 가능해야 한다.
 
List tmp = new Stack();
 
이게 가능해야 한다는 매우 지당한 사실이 리스코프 치환원칙을 의미한다.
 
출처

 

 

'자바' 카테고리의 다른 글

예외처리  (2) 2023.11.13
추상화란 추상클래스란  (0) 2023.10.23
리스코프 치환원칙  (0) 2023.10.18