Programming/Java

F009 - Inheritance, Composition

osean 2021. 5. 18. 03:52
✍️ 이번 μ‹œκ°„μ—λŠ” λ©˜ν† λ‹˜κ»˜μ„œ μ§ˆλ¬Έν•΄μ£Όμ…¨λ˜ 상속과 쑰합에 λŒ€ν•΄ λ‹€λ€„λ³ΌκΉŒ ν•œλ‹€.

사싀 Java λΌλŠ” μ–Έμ–΄κ°€ μ™œ 객체지ν–₯ 언어인지, μ΄λŸ¬ν•œ νŠΉμ§•μ„ 톡해 κ°€μ§€λŠ” 이점과 단점, 단점을 ν•΄κ²°ν•˜κΈ° μœ„ν•΄ μ–΄λ–€ 방법듀이 μžˆλŠ”μ§€ μ œλŒ€λ‘œ μ•Œμ§€ λͺ»ν•œ 채 μ‚¬μš©ν•˜κ³  μžˆμ—ˆλ‹€. (μ§€κΈˆκΉŒμ§€λ„!)

이번 기둝을 톡해 상속과 κ΅¬ν˜„, 그리고 μ‘°ν•©(Composition)을 νŒŒν—€μ³λ³΄μž!

상속 (Inheritance)

상속은 클래슀 λͺ… μš°μΈ‘μ— extends λΌλŠ” μ˜ˆμ•½μ–΄λ₯Ό 톡해 상속 받을 수 있고, 1개의 클래슀만 상속 받을 수 μžˆλ‹€.

μœ„μ˜ λ‹€μ΄μ–΄κ·Έλž¨μ„ ν™•μΈν•΄λ³΄μž. λ¨Όμ € Animal ν΄λž˜μŠ€κ°€ μ΅œμƒμœ„ 클래슀둜 μ‘΄μž¬ν•˜κ³  κ·Έ μ•„λž˜μ— Mammal, Bird 클래슀, 이 두 클래슀의 각각 μ•„λž˜μ— Dog, Whale, Eagle, Kiwi ν΄λž˜μŠ€κ°€ μ‘΄μž¬ν•œλ‹€. λ‹€μ΄μ–΄κ·Έλž¨μ—μ„œλŠ” ν•˜μœ„ ν΄λž˜μŠ€λ“€μ΄ μƒμœ„ 클래슀λ₯Ό ν–₯ν•΄ 바라보고 μžˆλŠ”λ° μ΄λŠ” 상속을 ν‘œν˜„ν•œ 것이닀.

Animal ν΄λž˜μŠ€μ™€ 그의 μžμ‹μΈ Mammal, Bird 클래슀의 μ½”λ“œλ₯Ό ν™•μΈν•΄λ³΄μž.

// Animal
public class Animal {
    public int eyes  = 2;
    public int mouse = 1;
    public int legs  = 4;

		public Animal() {
			System.out.println("λ‚˜λŠ” 동물이닀.");
		}

    public void move() {
        System.out.println("κ±Έμ–΄μ„œ μ΄λ™ν•œλ‹€.");
    }

    public void breeding() {
        System.out.println("λ²ˆμ‹ν•œλ‹€.");
    }

    public void getElements() {
        System.out.println("눈 : " + eyes + "개");
        System.out.println("μž… : " + mouse + "개");
        System.out.println("닀리 : " + legs + "개");
    }
}

// Mammal
public class Mammal extends Animal {

    public Mammal() {
        System.out.println("λ‚˜λŠ” 포유λ₯˜λ‹€.");
    }

    public Mammal(int legs) {
        this.legs = legs;
        System.out.println("닀리가 " + this.legs + "개λ₯Ό 가진 포유λ₯˜λ‹€.");
    }

    @Override
    public void breeding() {
        System.out.println("μž„μ‹ μœΌλ‘œ μžμ‹μ„ λ‚³μ•„ μ„ΈλŒ€λ₯Ό μž‡λŠ”λ‹€.");
    }
}

// Bird
public class Bird extends Animal {

    public int wings = 2;

    public Bird() {
        this.legs = 2;
        System.out.println("λ‚˜λŠ” μ‘°λ₯˜λ‹€.");
    }

    public Bird(int wings) {
        this.wings = wings;
        this.legs = 2;
        System.out.println("λ‚ κ°œκ°€ " + this.wings + "개λ₯Ό 가진 μ‘°λ₯˜λ‹€.");
    }

    public void fly() {
        System.out.println("λ‚ μ•„μ„œ μ΄λ™ν•œλ‹€.");
    }

    @Override
    public void breeding() {
        System.out.println("μ•Œμ„ λ‚³μ•„ μ„ΈλŒ€λ₯Ό μž‡λŠ”λ‹€.");
    }

    @Override
    public void getElements() {
        super.getElements();
        System.out.println("λ‚ κ°œ : " + wings + "개");
    }
}

μƒνƒœμ™€ 행동

λ¨Όμ € Animal ν΄λž˜μŠ€μ—λŠ” eyes, mouse, legs 3개의 멀버 ν•„λ“œμ™€ move(), breeding(), getElements() 3개의 λ©”μ†Œλ“œκ°€ μ •μ˜λ˜μ–΄ μžˆλ‹€. Animal을 μƒμ†λ°›λŠ” μžμ‹ 클래슀라면 κ³΅ν†΅μ μœΌλ‘œ 가지고 μžˆμ–΄μ•Ό ν•˜λŠ” μƒνƒœ(Field)와 행동(Method)이닀. 즉, Mammalκ³Ό Bird ν΄λž˜μŠ€λŠ” 3개의 멀버 ν•„λ“œμ™€ 3개의 λ©”μ†Œλ“œλ₯Ό 가지고 μžˆλ‹€λŠ” 의미이며, μ΄λŠ” SOLID μ›μΉ™μ—μ„œ Liskov Substitution Principle (λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙)에 μ†ν•˜λ©° 일반적인 IS-A 관계가 μ„±λ¦½λ˜μ–΄μ•Ό ν•œλ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€.

λ‹€ν˜•μ„± (Polymorphism)

Mammal ν΄λž˜μŠ€μ—μ„œλŠ” breeding(), Bird ν΄λž˜μŠ€μ—μ„œλŠ” legs ν•„λ“œμ™€ breeding() λ©”μ†Œλ“œκ°€ μž¬μ •μ˜ 되고 wings λΌλŠ” 멀버 ν•„λ“œμ™€ fly() λ©”μ†Œλ“œκ°€ μƒˆλ‘­κ²Œ μ„ μ–Έλ˜μ—ˆλ‹€. μ΄λŠ” λ‹€ν˜•μ„±(Polymorphism)의 νŠΉμ§•μ„ λ‚˜νƒ€λ‚΄λŠ”λ°, Overrideλ₯Ό 톡해 λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ μ„ μ–Έν•œ 멀버 ν•„λ“œ, λ©”μ†Œλ“œλ₯Ό μž¬μ •μ˜ν•˜κ±°λ‚˜ ν•΄λ‹Ή μžμ‹ ν΄λž˜μŠ€μ— μƒˆλ‘œμš΄ 멀버 ν•„λ“œλ‚˜ λ©”μ†Œλ“œλ₯Ό μ„ μ–Έν•˜λŠ” 것은 ν•˜λ‚˜μ˜ κ΅¬ν˜„μ²΄κ°€ 각기 λ‹€λ₯Έ μƒνƒœμ™€ 행동을 κ°€μ§ˆ 수 μžˆλ‹€λŠ” 것을 μ˜λ―Έν•œλ‹€.

이제 Mammal, Bird 클래슀의 μžμ‹ 클래슀 μ½”λ“œλ₯Ό 보며 좔가적인 νŠΉμ§•μ„ μ•Œμ•„λ³΄μž.

// Dog
public class Dog extends Mammal{

    public Dog() {
        System.out.println("λ‚˜λŠ” 강아지닀.");
    }
}

// Whale
public class Whale extends Mammal {
    public boolean fin = true;

    public Whale() {
        super(0);
        System.out.println("λ‚˜λŠ” κ³ λž˜λ‹€.");
    }

    protected void swim() {
        System.out.println("닀리 λŒ€μ‹  μ§€λŠλŸ¬λ―Έκ°€ μžˆμ–΄ ν—€μ—„μ³μ„œ μ΄λ™ν•œλ‹€.");
    }

    @Override
    public void move() {
        System.out.println("닀리가 μ—†μ–΄ κ±Έμ–΄μ„œ 이동 ν•  수 μ—†λ‹€.");
    }

    @Override
    public void getElements() {
        super.getElements();
        System.out.println("μ§€λŠλŸ¬λ―Έκ°€ μžˆλ‚˜? : " + fin);
    }
}

// Eagle
public class Eagle extends Bird {

    public Eagle() {
        System.out.println("λ‚˜λŠ” λ…μˆ˜λ¦¬λ‹€.");
    }
}

// Kiwi
public class Kiwi extends Bird {

    public Kiwi() {
        super(0);
        System.out.println("λ‚˜λŠ” ν‚€μœ„μƒˆλ‹€.");
    }

    @Override
    public void fly() {
        System.out.println("λ‚ κ°œκ°€ μ—†μ–΄ λ‚  수 μ—†λ‹€.");
    }
}

super()

λΆ€λͺ¨ 클래슀λ₯Ό 상속 받은 μžμ‹ ν΄λž˜μŠ€κ°€ new μƒμ„±μžλ‘œ 선언될 λ•Œ, μžμ‹ 클래슀만 λ©”λͺ¨λ¦¬μ— ν• λ‹Ήλ˜λŠ” 것이 μ•„λ‹ˆλΌ λΆ€λͺ¨ ν΄λž˜μŠ€λ„ ν•¨κ»˜ ν• λ‹Ήλœλ‹€. μžμ‹ 클래슀의 μƒμ„±μžκ°€ 호좜 될 λ•Œ, super()λΌλŠ” μ˜ˆμ•½μ–΄κ°€ ν•¨κ»˜ ν˜ΈμΆœλ˜λŠ”λ°, λ³„λ„λ‘œ λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ μƒμ„±μžλ₯Ό μ •μ˜ν•˜μ§€ μ•ŠλŠ” 경우 μ»΄νŒŒμΌλŸ¬μ— μ˜ν•΄ μžλ™μœΌλ‘œ μžμ‹ 클래슀의 μƒμ„±μžμ— μΆ”κ°€λ˜μ–΄ μžμ‹ ν΄λž˜μŠ€μ™€ λΆ€λͺ¨ ν΄λž˜μŠ€κ°€ λ©”λͺ¨λ¦¬μ— ν•¨κ»˜ 할당될 수 μžˆλ„λ‘ ν•œλ‹€.

단, λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ κΈ°λ³Έ μƒμ„±μžλ₯Ό μ •μ˜ν•˜μ§€ μ•Šκ³  맀개 λ³€μˆ˜λ₯Ό 받도둝 μƒμ„±μžλ₯Ό μ •μ˜ν•œλ‹€λ©΄ μžμ‹ 클래슀의 μƒμ„±μžμ— 맀개 λ³€μˆ˜λ₯Ό 넣은 super() μ˜ˆμ•½μ–΄λ₯Ό ν˜ΈμΆœν•΄μ•Όν•œλ‹€. 그렇지 μ•ŠμœΌλ©΄ μ»΄νŒŒμΌλŸ¬κ°€ λΆ€λͺ¨ 클래슀의 κΈ°λ³Έ μƒμ„±μžλ₯Ό 찾을 수 μ—†μ–΄ 컴파일 μ—λŸ¬κ°€ λ°œμƒν•œλ‹€. κ·Έλ ‡κΈ° λ•Œλ¬Έμ— μœ„ μ½”λ“œμ²˜λŸΌ λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ μ—¬λŸ¬ μƒμ„±μžλ₯Ό μ •μ˜ν•˜λŠ” 경우, κΈ°λ³Έ μƒμ„±μžλ₯Ό λͺ…μ‹œμ μœΌλ‘œ μ •μ˜ν•˜λŠ” 것이 μ’‹λ‹€.

λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙에 μ–΄κΈ‹λ‚˜λŠ” 경우

μ•žμ—μ„œ λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙을 잠깐 λ§›λ΄€λŠ”λ°, ν•΄λ‹Ή 원칙은 κ°œλ°© 폐쇄 원칙에 κΈ°λ°˜ν•˜λŠ” μ›μΉ™μœΌλ‘œ μ„œλΈŒ νƒ€μž…μ€ μ–Έμ œλ‚˜ 기반 νƒ€μž…μœΌλ‘œ ꡐ체할 수 μžˆμ–΄μ•Ό ν•˜λŠ” 원칙이닀. 근데 μœ„μ˜ μ½”λ“œμ—μ„œ λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙을 κΉ¨λŠ” μ½”λ“œκ°€ μ‘΄μž¬ν•œλ‹€.

Whale is a Mammal.
Kiwi is a Bird.

λ°”λ‘œ Mammal - Whale, Bird - Kiwi 의 상속 κ΄€κ³„μ—μ„œ λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ μ›μΉ™μ˜ IS-A 관계가 μ„±λ¦½ν•˜μ§€ λͺ»ν•œλ‹€. μ—¬κΈ°μ„œ IS-A κ΄€κ³„λž€, λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ μ •μ˜λœ λͺ¨λ“  것듀이 μžμ‹ ν΄λž˜μŠ€μ—μ„œ λͺ¨λ‘ μ‚¬μš©μ΄ κ°€λŠ₯ν•΄μ•Ό ν•˜λŠ” 것을 μ˜λ―Έν•œλ‹€. ν•˜μ§€λ§Œ μ—¬κΈ°μ„œ 객체의 κ΄€μ μœΌλ‘œ Mammal - Whale, Bird - Kiwi 관계λ₯Ό 듀여닀보면 그렇지 λͺ»ν•˜λ‹€.
(κ°μ²΄κ΄€μ μ˜ ν”„λ‘κ·Έλž˜λ°μ€ μΆ”μ²œν•˜μ§€ μ•ŠλŠ”λ‹€. μžμ„Έν•œ λ‚΄μš©μ€ Youtubeμ—μ„œ μš°ν…Œμ½” 검색!)

λ¨Όμ € Mammal ν΄λž˜μŠ€λŠ” Animal ν΄λž˜μŠ€μ—μ„œ μ •μ˜ν•œ eyes, mouse, legsλ₯Ό μž¬μ •μ˜ν•˜μ§€ μ•Šμ•˜λ‹€. κ·ΈλŸ¬λ―€λ‘œ Whale이 κ·ΈλŒ€λ‘œ 상속 λ°›λŠ”λ‹€λ©΄ 닀리가 4κ°œμ΄λ©΄μ„œ 걸을 수 μžˆλŠ” 이쒅 Whale이 νƒ„μƒν•œλ‹€. 즉, Whale은 Mammal에 μ†ν•˜λŠ” 객체가 λ§žμ§€λ§Œ λΆ€λͺ¨ 클래슀의 ꡬ쑰에 μ˜ν•΄ λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ μ •μ˜ν•œ move() λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ§€ λͺ»ν•˜κΈ° λ•Œλ¬Έμ— IS-A 관계λ₯Ό μ„±λ¦½ν•˜μ§€ λͺ»ν•΄ ν•΄λ‹Ή 원칙을 μœ„λ°°ν•œλ‹€.

Bird - Kiwi 의 관계도 λ™μΌν•˜λ‹€. Bird ν΄λž˜μŠ€λŠ” Animalμ—μ„œ μ •μ˜ν•œ legsλ₯Ό 2개둜 μž¬μ •μ˜ ν–ˆκ³ , Bird μž„μ„ 증λͺ…ν•˜κΈ° μœ„ν•΄ wings ν•„λ“œλ„ μ„ μ–Έν–ˆλ‹€. ν•˜μ§€λ§Œ 이λ₯Ό μƒμ†λ°›λŠ” KiwiλŠ” wings(λ‚ κ°œ)κ°€ μ—†κ³ , 이 λ•Œλ¬Έμ— fly() λ©”μ†Œλ“œλ₯Ό μ‚¬μš© ν•  수 μ—†λ‹€.

μ΄λ ‡κ²Œ λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙이 μ–΄κΈ‹λ‚˜λŠ” κ²½μš°λŠ” λ‹€μ–‘ν•˜κ²Œ μ‘΄μž¬ν•˜λ©°, 이에 μœ„λ°˜λ˜λŠ” 것은 곧 개방 폐쇄 원칙이 λ¬΄λ„ˆμ§€λŠ” 것이라고 봐도 λ¬΄λ°©ν•˜λ‹€. λ•Œλ¬Έμ— μ΄λŸ¬ν•œ 원칙을 μœ„λ°˜ν•˜μ§€ μ•ŠκΈ° μœ„ν•΄μ„œ Compositionμ΄λΌλŠ” κ°œλ…μ„ μ‚¬μš©ν•˜κΈ°λ„ ν•œλ‹€.

  • λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ λͺ…μ‹œν•œ κ°’μ—μ„œ λ²—μ–΄λ‚œ 값을 λ¦¬ν„΄ν•œλ‹€.
  • λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ λ²—μ–΄λ‚œ μ˜ˆμ™Έλ₯Ό λ°œμƒν•œλ‹€.
  • λΆ€λͺ¨ 클래슀λ₯Ό λ²—μ–΄λ‚œ κΈ°λŠ₯을 μˆ˜ν–‰ν•œλ‹€.
  • Array.asList() 와 Listκ°€ λ°”λ‘œ ν•΄λ‹Ή 원칙에 μ–΄κΈ‹λ‚˜λŠ” λŒ€ν‘œμ μΈ μ˜ˆμ‹œμ΄λ‹€.
    public class ArrayListTest() {
    		public static void main(String[] args) {
    				List list = Arrays.asList("aa","bb","cc");
            List list2 = current(list);
            list2.forEach(l -> System.out.println(l));
        }
    
        public static List current(List list) {
            String a = "hello";
            list.add(a);
            return list;
        }
    }
    
    /*
    Exception in thread "main" java.lang.UnsupportedOperationException
    	at java.util.AbstractList.add(AbstractList.java:148)
    	at java.util.AbstractList.add(AbstractList.java:108)
    	at Inheritance.InheritanceTest.main(ArrayListTest.java:42)
    */

μƒμ†μ˜ νŠΉμ§•λ§Œ 뽑아먹기

πŸ“ 상속은 extends μ˜ˆμ•½μ–΄λ₯Ό μž‰μš©ν•΄ μ΅œλŒ€ 1개의 클래슀λ₯Ό 상속 받을 수 μžˆλ‹€.

πŸ“ λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ λ³„λ„μ˜ μƒμ„±μž 선언이 μ—†λ‹€λ©΄ μžμ‹ ν΄λž˜μŠ€κ°€ 선언될 λ•Œ, μžμ‹ 클래슀의 μƒμ„±μžμ— μ»΄νŒŒμΌλŸ¬κ°€ super() μ˜ˆμ•½μ–΄λ₯Ό μΆ”κ°€ν•˜μ—¬ λΆ€λͺ¨, μžμ‹ ν΄λž˜μŠ€κ°€ λ©”λͺ¨λ¦¬μ— 할당될 수 μžˆλ„λ‘ ν•œλ‹€.

πŸ“ 상속은 λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙을 λ”°λ₯΄μ§€λ§Œ Array.asList()와 List μΈν„°νŽ˜μ΄μŠ€μ²˜λŸΌ 이λ₯Ό μœ„λ°˜ν•˜λŠ” κ²½μš°λ„ 있으며, 이λ₯Ό μœ„λ°˜ν•  경우 μΊ‘μŠν™”μ™€ 개방 폐쇄 원칙을 μœ„λ°˜ν•˜λŠ” 것이닀. (이λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ Composition을 μ‚¬μš©.)

πŸ“ @Override λ₯Ό 톡해 λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ μ •μ˜λœ λ©”μ†Œλ“œ, λ©”μ†Œλ“œλ₯Ό μžμ‹ ν΄λž˜μŠ€μ—μ„œ μž¬μ •μ˜λ₯Ό μˆ˜ν–‰ν•˜λ©΄μ„œ λ‹€ν˜•μ„±μ˜ νŠΉμ§•μ„ 가진닀.

πŸ“ 컴파일 μ‹œμ μ— 객체의 κ΅¬ν˜„μ²΄κ°€ κ²°μ •λ˜κΈ° λ•Œλ¬Έμ— 섀계에 μœ μ—°ν•˜μ§€ λͺ»ν•˜λ‹€.

πŸ“ μ»΄λΆ€λͺ¨ 클래슀의 λ‚΄λΆ€ κ΅¬ν˜„μ΄ 달라지면 ν•˜μœ„ 클래슀λ₯Ό κ³ μ³μ•Όν•˜λŠ” κ²½μš°κ°€ λ°œμƒν•˜λŠ”λ°, μ΄λŠ” μΊ‘μˆ ν™”λ₯Ό μœ„λ°˜ν•œλ‹€.

μ‘°ν•© (Composition)

μ•žμ—μ„œ μ•Œμ•„λ΄€λ˜ 것 처럼 Java의 상속은 μ–Έμ œλ‚˜ μ™„λ²½ν•˜μ§€λŠ” μ•Šλ‹€. 이λ₯Ό λ³΄μ™„ν•˜κ³  ν•΄κ²°ν•˜κΈ° μœ„ν•΄ Compositionμ΄λΌλŠ” κ°œλ…μ΄ λ“±μž₯ν•œλ‹€. Compositionμ΄λž€ κ΅¬μ„±μ΄λΌλŠ” 의미둜 클래슀의 멀버 λ³€μˆ˜μ— μ°Έμ‘° 객체λ₯Ό μ„ μ–Έν•˜κ³ , 이λ₯Ό μƒμ„±μžλ₯Ό 톡해 기쑴에 λ§Œλ“€μ–΄μ§„ 객체λ₯Ό μ£Όμž…ν•˜μ—¬ ν•΄λ‹Ή ν΄λž˜μŠ€μ—μ„œ μ°Έμ‘°ν•  객체λ₯Ό 상속 받지 μ•Šμ•„λ„ 클래슀의 μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λ‘œ μ°Έμ‘°ν•˜κ³  μžˆλŠ” 객체의 λ©”μ†Œλ“œλ₯Ό 호좜 ν•  수 μžˆλ„λ‘ μ„€κ³„ν•˜λŠ” 것을 μ˜λ―Έν•œλ‹€. 이λ₯Ό 톡해 ν•˜λ‚˜μ˜ 객체만 μ°Έμ‘° ν•  수 μžˆλŠ” Inheritance와 λ‹€λ₯΄κ²Œ, Composition은 ν•΄λ‹Ή κ°μ²΄μ—μ„œ μ°Έμ‘°ν•  μ—¬λŸ¬ 객체λ₯Ό μΈμŠ€ν„΄μŠ€ν™” ν•˜λ―€λ‘œμ¨ Inheritance보닀 λ§Žμ€ 객체λ₯Ό μ°Έμ‘° ν•  수 μžˆλ‹€λŠ” 이점이 μžˆλ‹€. λ˜ν•œ, μ°Έμ‘°ν•œ 객체의 λ©”μ†Œλ“œλ₯Ό μ°Έμ‘° κ°μ²΄μ—μ„œ μ˜λ„ν•œ κ°’μœΌλ‘œ μž¬μ •μ˜ 없이 λ¦¬ν„΄ν•˜μ—¬ μ‚¬μš© ν•  수 μžˆλ‹€λŠ” 점은 λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙과 개방 폐쇄 원칙을 잘 λ”°λ₯΄λŠ” κ²ƒμœΌλ‘œ λ³Ό 수 μžˆλ‹€.

κ·Έ 예둜, 햄버거 μ„ΈνŠΈλ₯Ό μƒκ°ν•΄λ³΄μž. 기쑴에 Inheritanceλ₯Ό μ΄μš©ν•΄ 햄버거 μ„ΈνŠΈλ₯Ό λ§Œλ“€μ—ˆλ‹€κ³  κ°€μ •ν–ˆμ„ λ•Œ, 햄버거와 콜라 그리고 κ°μžνŠ€κΉ€μ΄ 햄버거 μ„ΈνŠΈλ₯Ό 상속 λ°›λŠ”λ‹€. ν•˜μ§€λ§Œ μ΄λŠ” IS-A 관계λ₯Ό μ„±λ¦½ν•˜μ§€ λͺ»ν•œλ‹€. 햄버거와 κ°μžνŠ€κΉ€μ€ 먹을 수 μžˆμ§€λ§Œ 콜라처럼 λ§ˆμ‹€ μˆ˜λŠ” μ—†λ‹€. 즉, 이 μ„Έ 가지 κ°μ²΄λŠ” λΆ€λͺ¨ κ°μ²΄μ—μ„œ μ˜λ„ν•œ μƒνƒœμ™€ 행동을 κ·ΈλŒ€λ‘œ 물렀받지 λͺ»ν•˜λŠ”데, μ΄λŠ” 햄버거 μ„ΈνŠΈλŠ” 햄버거와 콜라 그리고 κ°μžνŠ€κΉ€ μžμ²΄κ°€ 될 수 μ—†λ‹€λŠ” 것을 μ˜λ―Έν•˜λ©° λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙 및 개방 폐쇄 원칙에 μ–΄κΈ‹λ‚œλ‹€.

public class HamburgerSet extends Menu {
    public Hamburger   hamburger;
    public Coke        coke;
    public FrenchFries frenchFries;

    public HamburgerSet(Hamburger hamburger, Coke coke, FrenchFries frenchFries) {
        this.hamburger = hamburger;
        this.coke = coke;
        this.frenchFries = frenchFries;

        this.name = hamburger.getName() + " μ„ΈνŠΈ";
        this.price = (this.hamburger.getPrice() + this.coke.getPrice() + this.frenchFries.getPrice()) - 2000;
        System.out.println(this.name + " 가격 : " + this.price + "원");
    }

    public void getHamburger() {
        System.out.println("λ‹¨ν’ˆ 메뉴λͺ… : " + this.hamburger.getName());
        System.out.println("λ‹¨ν’ˆ 가격 : " + this.hamburger.getPrice() + "원");
    }

    public void getCoke() {
        System.out.println("λ‹¨ν’ˆ 메뉴λͺ… : " + this.coke.getName());
        System.out.println("λ‹¨ν’ˆ 가격 : " + this.coke.getPrice() + "원");
    }

    public void getFrenchFries() {
        System.out.println("λ‹¨ν’ˆ 메뉴λͺ… : " + this.frenchFries.getName());
        System.out.println("λ‹¨ν’ˆ 가격 : " + this.frenchFries.getPrice() + "원");
    }
}

Composition의 νŠΉμ§• 뽑아먹기

πŸ“ λ‹€λ₯Έ 객체λ₯Ό μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λ‘œ μ„ μ–Έν•˜λ―€λ‘œμ¨ ν•΄λ‹Ή μΈμŠ€ν„΄μŠ€μ˜ λ©”μ†Œλ“œλ₯Ό 호좜 ν•  수 μžˆλ‹€.

πŸ“ μΈμŠ€ν„΄μŠ€λ‘œ μ„ μ–Έλœ 객체의 λ‚΄λΆ€ ꡬ쑰가 λ°”λ€Œλ”λΌλ„ 영ν–₯을 받지 μ•ŠλŠ”λ‹€.

πŸ“ μΈν„°νŽ˜μ΄μŠ€λ‘œ Composition을 κ΅¬ν˜„ν•˜λ©΄ κ΅¬ν˜„μ²΄μ˜ Type을 μ†μ‰½κ²Œ λ°”κΏ€ 수 μžˆλ‹€.

Inheritance, Composition

λ§₯λ„λ‚ λ“œμ˜ λ©”λ‰΄νŒμ„ 가지고 μ™”λ‹€. μ μ ˆν•œ μ˜ˆμ‹œκ°€ 아닐 수 μžˆμ§€λ§Œ, 직접 μ½”λ“œλ‘œ κ΅¬ν˜„ν•΄λ³΄λ‹ˆκΉŒ λ§Žμ€ κΈ€μ—μ„œ μ„€λͺ…ν•˜κ³  μžˆλŠ” λ‚΄μš©λ“€μ΄ 더 μ™€λ‹ΏλŠ” 것 κ°™μ•„ μ„€λͺ…해보렀고 ν•œλ‹€.

λ¨Όμ € Menu κ°μ²΄λŠ” λͺ¨λ“  κ°μ²΄λ“€μ˜ 쑰상이기 λ•Œλ¬Έμ— ν•˜μœ„ 객체듀은 Menu 객체λ₯Ό 상속 λ°›μœΌλ©°, μžμ‹ 객체듀을 κΈ°λ³Έ μƒμ„±μžλ₯Ό ν•˜λ‚˜μ”© 가지고 있고 이 λ•Œ ν•΄λ‹Ή 객체의 메뉴λͺ…(name)κ³Ό 가격(price)을 μž¬μ •μ˜ν•œλ‹€.

HamburgerSet의 경우, 인자둜 λ°›λŠ” 객체의 μ’…λ₯˜μ— 따라 μƒνƒœκ°€ 달라지며 μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λ‘œ μ„ μ–Έν•œ hamburger, coke, frenchfiesλ₯Ό μƒμ„±μžμ—μ„œ μ£Όμž… λ°›μ•„ 각 객체의 λ©”μ†Œλ“œλ₯Ό μ œμ•½μ—†μ΄ 호좜 ν•  수 μžˆλ‹€. μ΄λ ‡κ²Œ HamburgerSet을 μ—¬λŸ¬ μ°Έμ‘° 객체둜 κ΅¬μ„±ν•œ 것을 Composition이라고 ν•œλ‹€.

public class CompositionTest {
    public static void main(String[] args) {
        // λΉ…λ§₯ μ„ΈνŠΈλ§Œλ“€κΈ°
        // 코크 > λ‹€μ΄μ–΄νŠΈ 콜라둜 λ³€κ²½
        // ν”„λ ŒμΉ˜ν”„λΌμ΄ > 치즈 ν”„λ ŒμΉ˜ν”„λΌμ΄ λ³€κ²½
        Hamburger   bigMac            = new BigMac();
        Coke        dietCoke          = new DietCoke();
        FrenchFries cheeseFrenchFries = new CheeseFrenchFries();

        HamburgerSet bigMacSet = new HamburgerSet(bigMac, dietCoke, cheeseFrenchFries);
        bigMacSet.getHamburger();
        bigMacSet.getCoke();
        bigMacSet.getFrenchFries();

        System.out.println();

        // μΉ˜μ¦ˆλ²„κ±°
        // κΈ°λ³Έ ꡬ성
        Hamburger    cheeseBurger    = new CheeseBurger();
        Coke         coke            = new Coke();
        FrenchFries  frenchFries     = new FrenchFries();
        HamburgerSet cheeseBurgerSet = new HamburgerSet(cheeseBurger, coke, frenchFries);
        cheeseBurgerSet.getHamburger();
        cheeseBurgerSet.getCoke();
        cheeseBurgerSet.getFrenchFries();
    }
}
/*
	λΉ…λ§₯ μ„ΈνŠΈ 가격 : 7500원
	λ‹¨ν’ˆ 메뉴λͺ… : λΉ…λ§₯
	λ‹¨ν’ˆ 가격 : 4500원
	λ‹¨ν’ˆ 메뉴λͺ… : λ‹€μ΄μ–΄νŠΈ 콜라
	λ‹¨ν’ˆ 가격 : 2000원
	λ‹¨ν’ˆ 메뉴λͺ… : 치즈 ν”„λ ŒμΉ˜ν”„λΌμ΄
	λ‹¨ν’ˆ 가격 : 3000원
	
	μΉ˜μ¦ˆλ²„κ±° μ„ΈνŠΈ 가격 : 3500원
	λ‹¨ν’ˆ 메뉴λͺ… : μΉ˜μ¦ˆλ²„κ±°
	λ‹¨ν’ˆ 가격 : 2500원
	λ‹¨ν’ˆ 메뉴λͺ… : μ½”μΉ΄μ½œλΌ
	λ‹¨ν’ˆ 가격 : 1500원
	λ‹¨ν’ˆ 메뉴λͺ… : ν”„λ ŒμΉ˜ν”„λΌμ΄
	λ‹¨ν’ˆ 가격 : 1500원
*/

πŸ€” 사싀 μ§€κΈˆκΉŒμ§€ μ™œ 상속을 λ°›μ•„μ•Ό ν•˜λŠ”μ§€ λͺ¨λ₯Έμ±„ κ°œλ°œν–ˆμ—ˆλ‹€.
이번 μ‹œκ°„μ„ 톡해 직접 상속을 κ΅¬ν˜„ν•΄λ³΄λ©΄μ„œ μ–΄λ–»κ²Œ ν•˜λ©΄ 더 쒋은 μ½”λ“œλ‘œ μž‘μ„± ν•  수 μžˆμ„μ§€ λ§Žμ€ 고민을 ν•  수 μžˆμ—ˆλ˜ μ‹œκ°„μ΄μ˜€κ³ , Composition을 κ΅¬ν˜„ν•˜λ©° Spring Boot의 Bean 생성과 ꡉμž₯히 λΉ„μŠ·ν•˜λ‹€κ³  λŠκΌˆλŠ”λ° Spring에 λŒ€ν•΄μ„œ κ³΅λΆ€ν•˜κ²Œ 되면 쑰금 더 μ•Œμ•„λ³΄λ €κ³  ν•œλ‹€.

μ§€κΈˆκΉŒμ§€ 아무 μ˜λ―Έλ„ λͺ¨λ₯΄κ³  썼던 μ½”λ“œλ“€μ΄ λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ μ›μΉ™μ΄λ‚˜ 개방 폐쇄 원칙, λ‹€ν˜•μ„±κ³Ό μΊ‘μˆ ν™” λ“± λ‹€μ–‘ν•œ 이둠에 κ·Όκ±°ν•˜μ—¬ λ§Œλ“€μ–΄μ‘Œλ‹€λŠ” 것에 정말 λ†€λžλ‹€. 더 깊이 κ³΅λΆ€ν•΄μ„œ μ—¬λŸ¬ 사항듀을 κ³ λ €ν•œ 쒋은 μ½”λ“œλ₯Ό μž‘μ„± ν•  수 μžˆλŠ” 개발자둜 μ„±μž₯ν•΄μ•Όκ² λ‹€.

참고 자료

 

SOLID - LSP ( λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙) 에 λŒ€ν•˜μ—¬

[객체지ν–₯ SW μ„€κ³„μ˜ 원칙] β‘£ λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙 [객체지ν–₯ SW μ„€κ³„μ˜ 원칙] β‘£ λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙 κ³Όκ±° ν—λ¦¬μš°λ“œμ—μ„œλŠ” λ°°μš°λ“€μ΄ 쒋은 μ˜ν™”μ˜ 배역을 κ΅¬ν•˜κΈ° μœ„ν•΄ μ˜ν™”μ œμž‘μ‚¬μ— 자주 μ „ν™”λ₯Ό

guy-who-writes-sourcecode.tistory.com

'Programming > Java' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

F011 - java.lang.ref  (0) 2021.05.19
F010 - System.out.println(), Logger  (0) 2021.05.19
F008 - Garbage Collector  (2) 2021.05.16
F007 - JVM : Memory Architecture  (0) 2021.05.14
F006 - Throwable, Exception, Error  (0) 2021.05.11