본문으로 바로가기
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.



OCP - 개방 폐쇄 원칙


"소프트위어 엔티티(클래스, 모듈, 함수 등)는 확장에 대해서는 열려 있어야 하지만 변경에 대해서는 닫혀 있어야 한다. - 로버트 C 마틴


변경을 위한 비용은 가능한 줄이고 확장을 위한 비용은 가능한 극대화 해야 한다는 의미로, 요구사항의 변경이나 추가사항이 발생하더라도, 기존 구성요소는 수정이 일어나지 말아야 하며, 기존 구성요소를 쉽게 확장해서 재사용할 수 있어야 한다는 뜻이다.


아래 예제를 보면 SoundPlay와 SoundFile이 있다. 그리고 파일을 재생하면 되는데 요구사항으로 파일의 종류가 mp3일 수도 있고, wav파일 경우 play()가 달라진다. 어떻게 수정을 해야 할까 ?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class SoundPlay {
    List<SoundFile> soundList = new ArrayList<>();
    
    public void add(SoundFile file) {
        soundList.add(file);
    }
    
    public void play() {
        for(SoundFile file : soundList) {
            file.play();
        }
    }
}
 
class SoundFile {
    public String soundName;
    
    public SoundFile(String soundName) {
        this.soundName = soundName;
    }
    
    public void play() {
        System.out.println(soundName + " 재생 중");
    }
}
 
 
public class Test {
    public static void main(String[] args) {
        SoundPlay sp = new SoundPlay();
        sp.add(new SoundFile("바람이 분다"));
        sp.add(new SoundFile("불장난"));
        
        sp.play();
    }
}



다양한 방법이 있지만 나같은 경우에는 interface와 기존에 만들어진 SoundFile을 상속 받아서 새로운 Mp3, Wav 클래스를 만들어 play를 하게 변경하였다. 그리고 새로운 파일 형태가 나온다면 똑같이 interface와 SoundFile을 상속하여 플레이하면 정상적으로 수정되게 하였다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
class SoundPlay {
    List<PlayAlgorithm> soundList = new ArrayList<>();
    
    public void add(PlayAlgorithm file) {
        soundList.add(file);
    }
    
    public void play() {
        for(PlayAlgorithm file : soundList) {
            file.play();
        }
    }
}
 
interface PlayAlgorithm {
    public void play();
}
 
class SoundFile {
    public String soundName;
    
    public SoundFile(String soundName) {
        this.soundName = soundName;
    }
}
 
class Mp3 extends SoundFile implements PlayAlgorithm {
 
    public Mp3(String soundName) {
        super(soundName);
        // TODO Auto-generated constructor stub
    }
 
    @Override
    public void play() {
        // TODO Auto-generated method stub
        System.out.println(this.soundName + ".mp3 재생중.");
    }
}
 
class Wav extends SoundFile implements PlayAlgorithm {
 
    public Wav(String soundName) {
        super(soundName);
        // TODO Auto-generated constructor stub
    }
 
    @Override
    public void play() {
        // TODO Auto-generated method stub
        System.out.println(this.soundName + ".wav 재생중.");
    }
}
 
public class Test {
    public static void main(String[] args) {
        SoundPlay sp = new SoundPlay();
        PlayAlgorithm mp3 = new Mp3("바람이 분다");
        PlayAlgorithm wav = new Wav("불장난");
        
        sp.add(mp3);
        sp.add(wav);
        
        sp.play();
    }
}



OCP의 다른 예

데이터베이스 프로그래밍을 경험한 적이 있다면 OCP의 원칙을 제대로 경험한 것이 JDBC이다. 자바에서 JDBC를 사용하면 클라이언트는 데이터베이스가 오라클, Mysql, Maria 어떤 것이든 Connection 설정 부분을 제외하고는 변경할 부분이 없다.


자바에서도 개방 폐쇄 원칙이 적용된 부분은 윈도우, Linux, Mac 등등 다른 운영체제 상에서 구동될지에 대해서 걱정하지 않는다. 각 운영체제별 JVM과 목적 파일이 있기에 개발자는 구동 환경에 대해서 걱정하지 않고 개발하면 된다.


출처 - 스프링 입문을 위한 자바 객체 지향의 원리와 이해


위 코드는 내가 고심해서 작성을 해보았는데

원칙에 위배되지 않았는지 맞는지는 잘 모르겠습니다.

틀린 부분이나 지적사항이 있으면 말씀해주시면 감사합니다.