λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

πŸ“šμ½μ€ μ±… 정리/μžλ°” λ§ˆμŠ€ν„°λΆ

[μžλ°” λ§ˆμŠ€ν„°λΆ] 12μž₯ : λ””μžμΈνŒ¨ν„΄ 즐기기 - ꡬ쑰

12.3 ꡬ쑰에 κ΄€ν•œ νŒ¨ν„΄

12.3.1 Adapter νŒ¨ν„΄ - μΈν„°νŽ˜μ΄μŠ€μ— `ν˜Έν™˜μ„±μ΄ μ—†λŠ” 클래슀`듀을 μ‘°ν•©μ‹œν‚€κΈ°

κΈ°μ‘΄ μ‹œμŠ€ν…œμ„ μž¬μ‚¬μš©ν•˜μ—¬ μƒˆλ‘œμš΄ μ‹œμŠ€ν…œμ„ μ‚¬μš©ν•œλ‹€κ³  κ°€μ •ν•΄λ³΄μž. μ΄λ•Œ μƒˆλ‘œμš΄ μ‹œμŠ€ν…œμ€ μ§€κΈˆκΉŒμ§€ μ‚¬μš©ν•˜λ˜ λ©”μ„œλ“œμ™€λŠ” λ‹€λ₯Έ μΈν„°νŽ˜μ΄μŠ€λ₯Ό 가지고 μžˆλ‹€. 이 κ²½μš°μ—λŠ” κΈ°μ‘΄ μ‹œμŠ€ν…œμ— 손을 λŒ€μ„œ μˆ˜μ •μ„ ν•˜κ²Œ 되면 μ—„μ²­λ‚œ λ³€ν™”λ₯Ό κ°•μš”ν•˜κ²Œ λœλ‹€.

 

이 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•œ 'μˆ˜λ‹¨'이 Adapter νŒ¨ν„΄μ΄λ‹€.

이 νŒ¨ν„΄μ€ 'μΈν„°νŽ˜μ΄μŠ€'에 ν˜Έν™˜μ„±μ΄ μ—†λŠ” ν΄λž˜μŠ€λ“€μ„ μ‘°ν•©μ‹œν‚€λŠ” 것을 λͺ©μ μœΌλ‘œ ν•˜μ—¬ κΈ°μ‘΄ μ‹œμŠ€ν…œκ³Ό μƒˆλ‘œμš΄ μ‹œμŠ€ν…œμ˜ μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν‘μˆ˜ν•˜λŠ” Adapterλ₯Ό μ œκ³΅ν•˜μ—¬ '적은 λ³€κ²½μœΌλ‘œ κΈ°μ‘΄ μ‹œμŠ€ν…œμ„ μƒˆλ‘œμš΄ μ‹œμŠ€ν…œμ— μ μš©ν•  수 μžˆλ„λ‘' ν•œλ‹€.

 

Adapter νŒ¨ν„΄μ€ 두 가지 방법이 μžˆλ‹€.

1. 상속을 μ΄μš©ν•˜λŠ” 방법

2. μœ„μž„μ„ μ΄μš©ν•˜λŠ” 방법

 

상속을 μ΄μš©ν•˜λŠ” 방법

OldSystemμ΄λž€ ν΄λž˜μŠ€μ— κΈ°μ‘΄ λ©”μ„œλ“œλ“€μ΄ κ΅¬ν˜„λ˜μ–΄ 있고 Target μΈν„°νŽ˜μ΄μŠ€μ—λŠ” μƒˆλ‘œμš΄ λ©”μ„œλ“œ μ •μ˜κ°€ μžˆλ‹€.

이 λ•Œ Adapter에 OldSystem을 μƒμ†ν•˜κ³ (extends) Target을 κ΅¬ν˜„(Implements)ν•˜λ©΄ λœλ‹€.

 

μ΄λ ‡κ²Œ Adapterλ₯Ό λ§Œλ“€κ³  μ‚¬μš©ν•  λ•Œ Target μ°Έμ‘° λ³€μˆ˜μ— Adapter κ΅¬ν˜„μ²΄λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

public class OldSystem {
	public void oldProcess() {
    	// 기쑴 처리
    }
}

public interface Target {
	public void process() {
    	// 기쑴 처리
    }
}

public class Adapter extends OldSystem implements Target {
	@Override
	public void process() {
    	oldProcess();
    }
}

μœ„ μ½”λ“œμ²˜λŸΌ Adpaterλ₯Ό 톡해 Targetμ΄λΌλŠ” μƒˆλ‘œμš΄ μ‹œμŠ€ν…œμ˜ λ©”μ„œλ“œμ— κΈ°μ‘΄ μ‹œμŠ€ν…œμ˜ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λ„λ‘ ν•  수 μžˆλ‹€.

 

public class SampleMain {
	public static void main(String[] args) {
    	Target target = new Adapter();
        target.process();
    }
}

Adapterν΄λž˜μŠ€λŠ” κΈ°μ‘΄ 클래슀λ₯Ό μƒμ†ν•˜κ³  μƒˆλ‘œμš΄ μ‹œμŠ€ν…œμ˜ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ ν΄λž˜μŠ€μ΄λ‹€. μƒˆλ‘œμš΄ λ©”μ„œλ“œμΈ process() 호좜 μ‹œ κΈ°μ‘΄ λ©”μ„œλ“œκ°€ 호좜되게 κ΅¬ν˜„ν•¨μœΌλ‘œμ¨ κΈ°μ‘΄ μ‹œμŠ€ν…œμ„ κ·ΈλŒ€λ‘œ μ‚¬μš©ν•  수 있게 ν•œλ‹€.

 

μœ„μž„μ„ μ΄μš©ν•˜λŠ” 방법

μœ„μ²˜λŸΌ μƒˆλ‘œμš΄ μ‹œμŠ€ν…œμ΄ μΈν„°νŽ˜μ΄μŠ€κ°€ μ•„λ‹ˆλΌ μΆ”μƒν΄λž˜μŠ€λ‘œ μ„ μ–Έλœ 경우λ₯Ό κ°€μ •ν•΄λ³΄μž. 이 κ²½μš°μ—λŠ” κΈ°μ‘΄κ³Ό μƒˆλ‘œμš΄ 클래슀 두 개λ₯Ό 닀쀑 μƒμ†ν•΄μ•Όλ―€λ‘œ λΆˆκ°€λŠ₯ν•˜λ‹€. (λ˜ν•œ OldSystem이 final둜 μ„ μ–Έλ˜μ–΄ μžˆλŠ” κ²½μš°μ—λ„ 상속이 λΆˆκ°€λŠ₯해진닀.)

 

이런 κ²½μš°μ—λŠ” μœ„μž„μ„ μ‚¬μš©ν•˜λ©΄ 해결이 κ°€λŠ₯ν•˜λ‹€.

 

public class OldSystem {
	public void oldProcess() {
    	// 기쑴 처리
    }
}

public abstract Target {
	public abstract void process() {
    	// 기쑴 처리
    }
}

public class Adapter extends Target {

	private OldSystem oldSystem;
    
    public Adpater() {
    	this.oldSystem = new OldSystem();
    }
    
	@Override
	public void process() {
    	this.oldSystem.oldProcess();
    }
}

---------------------------------------

Adpater νŒ¨ν„΄μ€ μ‚¬μš©ν•˜κ³ μž ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ°•μ œμ μœΌλ‘œ λ°”κΎΈκ³  싢은 κ²½μš°μ— μ‚¬μš©ν•  수 μžˆλ‹€.

이미 μ‘΄μž¬ν•˜λŠ” 클래슀λ₯Ό λ³€κ²½ν•˜λŠ” 것이 μ•„λ‹ˆλΌ λ‹€λ₯Έ μΈν„°νŽ˜μ΄μŠ€μ—μ„œ ν˜ΈμΆœν•  λ•Œ μ‚¬μš©ν•  수 μžˆλ‹€.

 

ν”„λ ˆμž„μ›Œν¬λ₯Ό μ΄μš©ν•˜κ³  μžˆμ„ λ•Œ 'ν”„λ ˆμž„μ›Œν¬ λ‚΄λΆ€μ˜ 처리λ₯Ό λ‹€λ₯Έ λ°©λ²•μœΌλ‘œ ν˜ΈμΆœν•˜κ³  싢을 λ•Œ' μ‚¬μš©ν•  수 μžˆλ‹€.

12.3.2 Composite νŒ¨ν„΄ - μž¬κ·€μ  ꡬ쑰 μ‰½κ²Œ μ²˜λ¦¬ν•˜κΈ°

νŒŒμΌμ‹œμŠ€ν…œμ„ μ‰½κ²Œ ν‘œν˜„ν•˜λ €λ©΄ μ–΄λ–»κ²Œ ν•˜λ©΄ 될까?

일반적 νŒŒμΌμ‹œμŠ€ν…œμ—λŠ” 파일과 디렉토리가 μ‘΄μž¬ν•˜λŠ”λ° 이λ₯Ό κ΅¬λΆ„ν•˜μ§€ μ•Šκ³  μ²˜λ¦¬ν•œλ‹€λ©΄ λ”μš± νŽΈν•  것이닀.

 

이λ₯Ό κ΅¬ν˜„ν•˜κΈ° μœ„ν•œ μˆ˜λ‹¨μ΄ λ°”λ‘œ 'Compsite' νŒ¨ν„΄μ΄λ‹€.

 

public interface Entry {
	void add(Entry entry);
    
    void remove();
    
    void rename(String name);
}

public class File implements Entry {
	private String name;
    
    public File(String name) {
    	this.name = name;
    }
    
    @Override
    public void add(Entry entry) {
    	throw new UnsupportedOperationException();
    }
    
    @Override
    public void remove() {
    	System.out.println(this.name + "λ₯Ό μ‚­μ œν–ˆλ‹€.");
    }
    
    @Override
    public void rename(String name) {
    	this.name = name;
    }
}

public class Directory implements Entry {
	private String name;
    
    private List<Entry> list;
    
    public Directory(String name) {
    	this.name = name;
        this.list = new ArrayList<>();
    }
    
    @Override
    public void add(Entry entry) {
    	list.add(entry);
    }
    
    @Override
    public void remove() {
    	Iterator<Entry> itr = list.iterator();
        while(itr.hasNext()) {
        	Entry entry = itr.next();
            entry.remove();
        }
   		System.out.println(this.name + "λ₯Ό μ‚­μ œν–ˆλ‹€.");
    }
    
    @Override
    public void rename(String name) {
    	this.name = name;
    }
}

μœ„ μ½”λ“œλŠ” '파일'κ³Ό '디렉토리' λͺ¨λ‘ Entry μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λ„λ‘ ν–ˆλ‹€. 이λ₯Ό 톡해 두 클래슀λ₯Ό λ™μΌμ‹œν•˜μ—¬ μ²˜λ¦¬ν•  수 있게 ν•˜μ˜€λ‹€.

 

public Class SampleMain {
	public static void main(String... args) {
    	File file1 = new File("file1");
        File file2 = new File("file2");
        File file3 = new File("file3");
        File file4 = new File("file4");
        
        Directory dir1 = new Directory("dir1");
        dir1.add(file1);
        
        Directory dir2 = new Directory("dir1");
        dir2.add(file2);
        dir2.add(file3);
        
        dir1.remove();
    }
}

Composite νŒ¨ν„΄μ„ μ΄μš©ν•¨μœΌλ‘œμ¨ μž¬κ·€μ μΈ ꡬ쑰의 기술이 μš©μ΄ν•˜κ²Œ 되고 μœ μ§€λ³΄μˆ˜μ„±λ„ ν–₯μƒμ‹œν‚¬ 수 μžˆλ‹€.

ν˜„μ—…μ˜ ν”„λ‘œκ·Έλž¨μ—μ„œλŠ” 트리 ꡬ쑰의 데이터λ₯Ό ν‘œν˜„ν•  λ•Œ μ‚¬μš©ν•œλ‹€.