파이널프로젝트-주간블로깅 3회

Moon·2024년 9월 3일

Mini, Final

목록 보기
6/8

IS-A 관계를 통해 생성된 클래스 및 객체는 상속 관계에서 둘은 밀접하게 결합되므로 부모 또는 기저 클래스의 명세에 변경이 발생하면 코드가 손상될 위험이 있습니다. 대신에 이러한 밀접한 관계는 클래스 계층구조에서 좀 더 안정적인 기반을 마련한다는 의미이기도 합니다. 게다가 상위 클래스의 기능을 하위 클래스가 물려받아 사용할 수 있는 장점도 있습니다.

반면 HAS-A 방식으로 생성된 클래스 및 객체는 느슨하게 결합됩니다. 이는 상속에 비해서 명세에 변경이 발생하더라도 구성 요소를 쉽게 변경할 수 있다는 의미입니다(코드의 손상이 적거나 없다는 의미입니다). 이러한 점에서 더 많은 유연성을 제공합니다. 하지만, HAS-A 방식은 상속보다 항상 낫다고 말할 정도로 단순한 문제가 아니며 실상은 더 복잡합니다.

has-a

객체의 합성/포함

class Car {

    String name;
    Accelerator accelerator;
    Engine engine;
    Handle handle;
    Wheel wheel;

    Car(String name, Accelerator accelerator, Engine engine, Handle handle, Wheel wheel) {
        this.name = name;
        this.accelerator = accelerator;
        this.engine = engine;
        this.handle = handle;
        this.wheel = wheel;
    }
}

Accelerator accelerator = new Accelerator("이쁜 자동차");
Engine engine = new Engine("이쁜 자동차");
Handle handle = new Handle();
Wheel wheel = new Wheel("빠른 바퀴");

Car car = new Car("이쁜 자동차", accelerator, engine, handle, wheel);

is a

다형성

class A {
	public String x() {
    	return "A.x";
    }
}

class B extends A {
	public String y() {
    	return "y"
}

A obj = new B(); 
obj.x(); //A.x
obj.y(); //에러. obj의 데이터타입은 A이기 때문. 

class A {
	public String x() {
    	return "A.x";
    }
}

class B extends A {
	public String x() {
    	return "B.x"; //오버라이딩
	public String y() {
    	return "y"
}

class B2 extends A {
	public String x() {
    	return "B2.x";
}    

A obj = new B(); 
A obj2 = new B2();
obj.x(); //B.x
  • 클래스 B의 인스턴스를 클래스 A의 변수에 담았음. 부모 A의 행세를 함.
  • A의 데이터타입을 한 B클래스의 인스턴스(B가 A를 상속)
  • A가 가진 메소드만 실행가능하며 B만 갖고 있는 메소드는 실행불가. 단, B에서 A의 메소드를 오버라이딩하면 실행할 수 있음.
  • 쉽게 말하면 부모타입으로 객체 생성시 부모가 허락한 메소드만(동일한 메소드명 = 오버라이딩) 실행가능

왜 이렇게 하는가?
결과: 인스턴스가 A인것처럼 동작하게 할 수 있음.

public class Dog {
    protected String color;

    public void bite() {
        System.out.println("깨물다");
    }

    public void bark() {
        System.out.println("짖는다");
    }
}

public class Bulldog extends Dog {

}

public class Retriever extends Dog {
    public void swim() {
        System.out.println("수영하다");
    }
}

다형성

  1. 상속구조가 있을 때 다형성을 쓸 수 있음.
  2. 하나의 객체 인스턴스가 여러가지 자료형을 가질 수 있는 것
  3. 다형성은 is a 관계
  4. 자식객체는 부모객체가 될 수 있음. 부모객체는 자식객체가 될 수 없음.
  5. 자식객체는 부모객체의 성질을 가지고 메모리 공간에 적재됌.
  6. instanceOf로 is a 관계 확인.
		<--- 이 순서로 읽음. 
Bulldog bulldog = new Bulldog(); //Bulldog is a Bulldog

Dog dog = new BullDog(); //Bulldog is a Dog

Retriever retriever = new Retriever(); //Retriever is a Retriever

Dog dog = new Retriever(); //Retriever is a Dog 

형변환

Dog dog = new Retriever();
Retriever retriever = (Retriever)dog;
retriever.swim(); //가능

Dog dog = new Bulldog(); //Bulldog is a Dog
Bulldog bulldog = (Bulldog)dog; 
-> DogBulldog의 구성은 같으므로 형변환 가능. 

Dog dog = new Dog(); //Dog is a Dog
Retirever retriever = (Retriever)dog; //에러 발생, 개는 리트리버가 될 수 없다.
-> Dog.swim 메소드가 없으므로 형변환 불가. 

.instanceOf

다형성을 쓰는 이유

package day08;

public class EX04 {
    public static void main(String[] args) {
        //다형성 안 쓸 경우
        Chicken chicken = new Chicken();
        chicken.cry();

        Cow cow = new Cow();
        cow.cry();

        //다형성 쓸 경우
        Farm farm = new Farm();

        Animal chicken_ = new Chicken();
        farm.sound(chicken_);

        Animal cow_ = new Cow();
        farm.sound(cow_);

        //다형성을 쓰는 이유: 메소드에 업캐스팅된 부모타입의 변수를 넣어서, 자식 클래스 아무나 올 수 있게.
        //만약 안쓰면 Farm안데 sound(Cow cow), sound(Chicken chicken) 처럼 동물 수만큼 메서드를 생성해서 계속 오버로딩해야함.
        //Cow와 Chicken이 공통점은 Animal임.
    }
}

class Farm {
    public void sound(Animal animal) {
        animal.cry();
    }
}

class Animal {
    public void cry() {
        System.out.println("소리 없음");
    }
}

class Chicken extends Animal {
    @Override
    public void cry() {
        System.out.println("꼬꼬댁");
    }

    public void fly() {
        System.out.println("파닥파닥");
    }
}

class Cow extends Animal {
    @Override
    public void cry() {
        System.out.println("음메");
    }

    public void eat() {
        System.out.println("우물우물");
    }
}

0개의 댓글