# [Java] ์ปดํฌ์ง€์…˜(Composition)


์ปดํฌ์ง€์…˜ : ๊ธฐ์กด ํด๋ž˜์Šค๊ฐ€ ์ƒˆ๋กœ์šด ํด๋ž˜์Šค์˜ ๊ตฌ์„ฑ์š”์†Œ๊ฐ€ ๋˜๋Š” ๊ฒƒ
์ƒ์†(Inheritance)์˜ ๋‹จ์ ์„ ์ปค๋ฒ„ํ•  ์ˆ˜ ์žˆ๋Š” ์ปดํฌ์ง€์…˜์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž

์šฐ์„  ์ƒ์†(Inheritance)์ด๋ž€, ํ•˜์œ„ ํด๋ž˜์Šค๊ฐ€ ์ƒ์œ„ ํด๋ž˜์Šค์˜ ํŠน์„ฑ์„ ์žฌ์ •์˜ ํ•œ ๊ฒƒ์„ ๋งํ•œ๋‹ค. ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜์—ฌ ์ž์‹์— ๋งž๊ฒŒ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋“ฑ, ์ƒ๋‹นํžˆ ๋งŽ์ด ์“ฐ์ด๋Š” ๊ฐœ๋…์ด๋ฉด์„œ ํ™œ์šฉ๋„๋„ ๋†’๋‹ค.

ํ•˜์ง€๋งŒ ์žฅ์ ๋งŒ ์กด์žฌํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์ƒ์†์„ ์ œ๋Œ€๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ์œ ์—ฐ์„ฑ์„ ํ•ด์น  ์ˆ˜ ์žˆ๋‹ค.


# ๊ตฌํ˜„ ์ƒ์†(ํด๋ž˜์Šคโ†’ํด๋ž˜์Šค)์˜ ๋‹จ์ 

  1. ์บก์Šํ™”๋ฅผ ์œ„๋ฐ˜

  2. ์œ ์—ฐํ•˜์ง€ ๋ชปํ•œ ์„ค๊ณ„

  3. ๋‹ค์ค‘์ƒ์† ๋ถˆ๊ฐ€๋Šฅ


# ์˜ค๋ฅ˜์˜ ์˜ˆ์‹œ

๋‹ค์Œ์€, HashSet์— ์š”์†Œ๋ฅผ ๋ช‡ ๋ฒˆ ์‚ฝ์ž…ํ–ˆ๋Š”์ง€ count ๋ณ€์ˆ˜๋กœ ์ฒดํฌํ•˜์—ฌ ์ถœ๋ ฅํ•˜๋Š” ์˜ˆ์ œ๋‹ค.

public class CustomHashSet<E> extends HashSet {
    private int count = 0;

    public CustomHashSet(){}

    public CustomHashSet(int initCap, float loadFactor){
        super(initCap,loadFactor);
    }

    @Override
    public boolean add(Object o) {
        count++;
        return super.add(o);
    }

    @Override
    public boolean addAll(Collection c) {
        count += c.size();
        return super.addAll(c);
    }

    public int getCount() {
        return count;
    }

}

add์™€ addAll ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ ์‹œ, count ๋ณ€์ˆ˜์— ํ•ด๋‹น ํšŸ์ˆ˜๋ฅผ ๋”ํ•ด์ฃผ๋ฉด์„œ, getCount()๋กœ ํ˜ธ์ถœ ์ˆ˜๋ฅผ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ, ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•ด๋ณด๋ฉด ์›ํ•˜๋Š” ๊ฐ’์„ ์–ป์ง€ ๋ชปํ•œ๋‹ค.


public class Main {
    public static void main(String[] args) {
        CustomHashSet<String> customHashSet = new CustomHashSet<>();
        List<String> test = Arrays.asList("a","b","c");
        customHashSet.addAll(test);

        System.out.println(customHashSet.getCount()); // 6
    }
}

a, b, c์˜ 3๊ฐ€์ง€ ์š”์†Œ๋งŒ ๋ฐฐ์—ด์— ๋‹ด์•„ ์ „๋‹ฌํ–ˆ์ง€๋งŒ, ์‹ค์ œ getCount ๋ฉ”์„œ๋“œ์—์„œ๋Š” 6์ด ์ถœ๋ ฅ๋œ๋‹ค.

์ด๋Š” CustomHashSet์—์„œ ์ƒ์†์„ ๋ฐ›๊ณ  ์žˆ๋Š” HashSet์˜ ๋ถ€๋ชจ ํด๋ž˜์Šค์ธ AbstractCollection์˜ addAll ๋ฉ”์„œ๋“œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.


// AbstractCollection์˜ addAll ๋ฉ”์„œ๋“œ
public boolean addAll(Collection<? extends E> c) {
    boolean modified = false;
    for (E e : c)
        if (add(e))
            modified = true;
    return modified;
}

ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ๋ณด๋ฉด, add(e)๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์™œ 6์ด ๋‚˜์˜จ์ง€ ์ดํ•ด๊ฐ€ ๋˜์—ˆ์„ ๊ฒƒ์ด๋‹ค.

์šฐ๋ฆฌ๋Š” CustomHashSet์—์„œ add() ์™€ addAll()๋ฅผ ๋ชจ๋‘ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜์—ฌ count ๋ณ€์ˆ˜๋ฅผ ๊ฐ๊ฐ ์ฆ๊ฐ€์‹œ์ผœ์คฌ๋‹ค. ๊ฒฐ๊ตญ ๋‘ ๋ฉ”์„œ๋“œ๊ฐ€ ๋ชจ๋‘ ์‹คํ–‰๋˜๋ฉด์„œ ์ด 6๋ฒˆ์˜ count๊ฐ€ ์ €์žฅ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

๋”ฐ๋ผ์„œ ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„  ๋‘ ๋ฉ”์†Œ๋“œ ์ค‘์— ํ•˜๋‚˜์˜ count๋ฅผ ์ฆ๊ฐ€ํ•˜๋Š” ๊ณณ์„ ์ง€์›Œ์•ผํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Ÿฌ๋ฉด ๋ˆˆ์œผ๋กœ ๋ดค์„ ๋•Œ ์ฝ”๋“œ์˜ ๋…ผ๋ฆฌ๊ฐ€ ๊นจ์งˆ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ์ถ”ํ›„์— HashSet ํด๋ž˜์Šค์— ๋ณ€๊ฒฝ์ด ์ƒ๊ธฐ๊ธฐ๋ผ๋„ ํ•œ๋‹ค๋ฉด ํฐ ์˜ค๋ฅ˜๋ฅผ ๋ฒ”ํ•  ์ˆ˜๋„ ์žˆ๊ฒŒ ๋œ๋‹ค.

๊ฒฐ๊ณผ๋ก ์ ์œผ๋กœ, ์œ„์™€ ๊ฐ™์ด ์ƒ์†์„ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ์œ ์—ฐํ•˜์ง€ ๋ชปํ•จ๊ณผ ์บก์Šํ™”์— ์œ„๋ฐฐ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ฌธ์ œ์ ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.



# ๊ทธ๋ ‡๋‹ค๋ฉด ์ปดํฌ์ง€์…˜์€?

์ƒ์†์ฒ˜๋Ÿผ ๊ธฐ์กด์˜ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅ(extend)ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ private ํ•„๋“œ๋กœ ๊ธฐ์กด ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋ฐฉ์‹์ด ๋ฐ”๋กœ ์ปดํฌ์ง€์…˜์ด๋‹ค.

forwarding์ด๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค.

์ƒˆ๋กœ์šด ํด๋ž˜์Šค์ด๊ธฐ ๋•Œ๋ฌธ์—, ์—ฌ๊ธฐ์„œ ์–ด๋– ํ•œ ์ƒ์„ฑ ์ž‘์—…์ด ์ผ์–ด๋‚˜๋”๋ผ๋„ ๊ธฐ์กด์˜ ํด๋ž˜์Šค๋Š” ์ „ํ˜€ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ด ํ•ต์‹ฌ์ด๋‹ค.

์œ„์˜ ์˜ˆ์ œ๋ฅผ ๊ฐœ์„ ํ•˜์—ฌ, ์ปดํฌ์ง€์…˜ ๋ฐฉ์‹์œผ๋กœ ๋งŒ๋“ค์–ด๋ณด์ž


public class CustomHashSet<E> extends ForwardingSet {
    private int count = 0;

    public CustomHashSet(Set<E> set){
        super(set);
    }

    @Override
    public boolean add(Object o) {
        count++;
        return super.add(o);
    }

    @Override
    public boolean addAll(Collection c) {
        count += c.size();
        return super.addAll(c);
    }

    public int getCount() {
        return count;
    }

}
public class ForwardingSet<E> implements Set {

    private final Set<E> set;

    public ForwardingSet(Set<E> set){
        this.set=set;
    }

    @Override
    public int size() {
        return set.size();
    }

    @Override
    public boolean isEmpty() {
        return set.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return set.contains(o);
    }

    @Override
    public Iterator iterator() {
        return set.iterator();
    }

    @Override
    public Object[] toArray() {
        return set.toArray();
    }

    @Override
    public boolean add(Object o) {
        return set.add((E) o);
    }

    @Override
    public boolean remove(Object o) {
        return set.remove(o);
    }

    @Override
    public boolean addAll(Collection c) {
        return set.addAll(c);
    }

    @Override
    public void clear() {
        set.clear();
    }

    @Override
    public boolean removeAll(Collection c) {
        return set.removeAll(c);
    }

    @Override
    public boolean retainAll(Collection c) {
        return set.retainAll(c);
    }

    @Override
    public boolean containsAll(Collection c) {
        return set.containsAll(c);
    }

    @Override
    public Object[] toArray(Object[] a) {
        return set.toArray();
    }
}

CustomHashSet์€ Set ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ implementsํ•œ ForwardingSet์„ ์ƒ์†ํ•œ๋‹ค.

์ด๋กœ์จ, HashSet์˜ ๋ถ€๋ชจํด๋ž˜์Šค์— ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๊ณ  ์˜ค๋ฒ„๋ผ์ด๋”ฉ์„ ํ†ตํ•ด ์›ํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

public class Main {
    public static void main(String[] args) {
        CustomHashSet<String> customHashSet = new CustomHashSet<>(new HashSet<>());
        List<String> test = Arrays.asList("a","b","c");
        customHashSet.addAll(test);

        System.out.println(customHashSet.getCount()); // 3
    }
}

CustomHashSet์ด ์›ํ•˜๋Š” ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€ ForwardingSet์€ ์œ„์ž„(Delegation) ์—ญํ• ์„ ๊ฐ€์ง„๋‹ค.

์›๋ณธ ํด๋ž˜์Šค๋ฅผ wrapping ํ•˜๋Š”๊ฒŒ ๋ชฉ์ ์ด๋ฏ€๋กœ, Wrapper Class๋ผ๊ณ  ๋ถ€๋ฅผ ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ˜„์žฌ ์ž‘์—…ํ•œ ์ด๋Ÿฌํ•œ ํŒจํ„ด์„ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ์–ด๋– ํ•œ ํด๋ž˜์Šค๋ฅผ Wrapper ํด๋ž˜์Šค๋กœ ๊ฐ์‹ธ๋ฉฐ, ๊ธฐ๋Šฅ์„ ๋ง์”Œ์šด๋‹ค๋Š” ์˜๋ฏธ๋‹ค.


์ƒ์†์„ ์“ฐ์ง€๋ง๋ผ๋Š” ์ด์•ผ๊ธฐ๋Š” ์•„๋‹ˆ๋‹ค. ์ƒ์†์„ ์‚ฌ์šฉํ•˜๋Š” ์ƒํ™ฉ์€ LSP ์›์น™์— ๋”ฐ๋ผ IS-A ๊ด€๊ณ„๊ฐ€ ๋ฐ˜๋“œ์‹œ ์„ฑ๋ฆฝํ•  ๋•Œ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ํ˜„์‹ค์ ์œผ๋กœ ์ถ”ํ›„์˜ ๋ณ€ํ™”๊ฐ€ ์ด๋ฃจ์–ด์งˆ ์ˆ˜ ์žˆ๋Š” ๋ฐฉํ–ฅ์„ฑ์„ ๊ณ ๋ คํ•ด๋ดค์„ ๋•Œ ์ด๋ ‡๊ฒŒ ๋ช…ํ™•ํ•œ IS-A ๊ด€๊ณ„๋ฅผ ์„ฑ๋ฆฝํ•œ๋‹ค๊ณ  ๋ณด์žฅํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋Œ€๋ถ€๋ถ„์ด๋‹ค.

๊ฒฐ๊ตญ ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด์„ , ์ปดํฌ์ง€์…˜ ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ์„ค๊ณ„๋ฅผ ํ•  ๋•Œ ์œ ์—ฐํ•จ์„ ๊ฐ–์ถ”๊ณ  ๋‚˜์•„๊ฐˆ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.



# [์ฐธ๊ณ  ์ž๋ฃŒ]

์ตœ์ข… ์ˆ˜์ • : 12/17/2022, 7:23:59 AM