Blog
컴퓨터 공학
소프트웨어 아키텍쳐
객체지향 프로그래밍

객체 지향 프로그래밍

  • 객체 지향 프로그래밍의 특징
  1. 정보 은닉
  2. 상속
  3. 다형성

다형성(Polymorphism)

하나의 메세지에 대해서 하위 클래스들이 서로 다르게 반응한다.

  • 장점
  1. 메서드의 동작이 수정이 되더라도 부모의 메서드만 수정하면 된다.
  2. 확장이 용이하다.
  3. 부모의 메서드를 재정의 했다고 가정할 때, 부모를 통해서 자식의 메서드를 수행할 수 있다.
다형성의 올바른 예
public class Main {
    public  static  void main(String[] args) {
        Animal animal = new Dog();
        animal.eat();
        animal = new Cat();
        animal.eat();
    }
}
 
class Animal {
    void eat() {
        System.out.println("Eat");
    }
}
 
class Dog extends Animal {
    @Override
    void eat() {
        System.out.println("개처럼 먹다.");
    }
}
 
class Cat extends Animal{
    @Override
    void eat() {
        System.out.println("고양이처럼 먹다.");
    }
}

다형성의 조건

  1. 상속관계
  2. Override(재정의)
  3. Upcasting(업캐스팅)
  4. 동적 바인딩

다형성 인자

다형성 인수를 활용하는 기본적인 방법은 아래와 같다. 자식 클래스의 종류에 따라서 다른 동작을 하도록 하기 위해서 여러 개의 메서드를 선언하는게 아니라 인자를 부모 클래스로 받아주면 된다. 이 때, Override된 메서드 이 외의 메서드를 사용하게 되면 에러가 난다.

public class Main {
    public  static  void main(String[] args) {
        Dog d = new Dog();
        Cat c = new Cat();
        display(d);
        display(c);
    }
 
    public static void display(Animal a) {
        a.eat();
    }
}

타입 검사와 캐스팅

다음과 같이 instanceof 연산자를 사용해서 타입 검사를 할 수 있고 true가 출력되는 경우에 대해서 DownCasting이 가능하다.

public static void display(Animal a) {
    a.eat();
    if(a instanceof Cat) {
        ((Cat) a).night();
    }
}

다형성 배열

public  static  void main(String[] args) {
    Animal[] animals = new Animal[2];
    Cat cat = new Cat();
    Dog dog = new Dog();
    animals[0] = cat;
    animals[1] = dog;
 
    for(Animal animal: animals) {
        animal.eat();
    }
}

다형성의 보장

다형성을 보장한다 > 부모가 명령을 내리면 자식이 반드시 동작을 해야 한다 > 반드시 재정의가 되어야 한다
다형성에서 자식이 반드시 동작을 한다는 의미는 자식만의 메서드로 동작을 해야 한다는 것을 의미한다.

Abstract 다형성

메서드를 abstract로 만들게 되면 반드시 Override 해줘야 사용할 수 있다.

abstract class Animal {
    abstract void eat();
}
 
 
class Dog extends Animal {
    @Override
    public void eat() {
 
    }
}
 
class Cat extends Animal{
    @Override
    public void eat() {
 
    }
}

Interface의 다형성

abstarct는 구현 메서드가 들어갈 수 있는데 이는 다음과 같은 문제를 불러올 수 있다.

  1. 구현체의 메서드가 상속받은 특정한 클래스에서는 사용되지 않는 경우
  2. 만약 상속 받은 객체에서 추상 클래스의 필드에 직접 접근할 수 있게 되면 이는 캡슐화를 깨트리는 것이다.
  3. 구현 메서드가 클래스가 동작하는데 있어서 아주 중요한 기능을 하는 경우 (예를 들면 템플릿 메서드 패턴)

이러한 문제를 막고자 구현체를 가질 수 없는 class 인 Interface를 고안했다.

public interface Remocon {
    void chUp();
    void chDown();
    void volUp();
    void volDown();
    // 에러러 발생
    // public void internet() {
    // System.out.println("인터넷이 구동된다.");
    // }
}
 
// abstract와 다르게 implements를 사용한다.
// 다중 상속(구현)이 가능하다.
class Radio implements Remocon {
    @Override
    public void chUp() {
        System.out.println("라디오 채널이 올라간다.");
    }
 
    @Override
    public void chDown() {
        System.out.println("라디오 채널이 내려간다.");
    }
 
    @Override
    public void volUp() {
        System.out.println("라디오 볼륨이 올라간다.");
    }
 
    @Override
    public void volDown() {
        System.out.println("라디오 채널이 내려간다.");
    }
}
 
class TV implements Remocon {
    @Override
    public void chUp() {
        System.out.println("TV 채널이 올라간다.");
    }
 
    @Override
    public void chDown() {
        System.out.println("TV 채널이 내려간다.");
    }
 
    @Override
    public void volUp() {
        System.out.println("TV 볼륨이 올라간다.");
    }
 
    @Override
    public void volDown() {
        System.out.println("TV 채널이 올라간다.");
    }
}