|
| 1 | +# An overview of design pattern - SOLID, GRASP |
| 2 | + |
| 3 | +먼저 디자인 패턴을 공부하기 전에 Design Principle인 SOLID와 GRASP에 대해서 알아보자 |
| 4 | + |
| 5 | + |
| 6 | +# Design Smells |
| 7 | +design smell이란 나쁜 디자인을 나타내는 증상같은 것이다. |
| 8 | + |
| 9 | +아래 4가지 종류가 있다. |
| 10 | +1. Rigidity(경직성) |
| 11 | + 시스템이 변경하기 어렵다. 하나의 변경을 위해서 다른 것들을 변경 해야할 때 경직성이 높다. |
| 12 | + 경직성이 높다면 non-critical한 문제가 발생했을 때 관리자는 개발자에게 수정을 요청하기가 두려워진다. |
| 13 | + |
| 14 | +2. Fragility(취약성) |
| 15 | + 취약성이 높다면 시스템은 어떤 부분을 수정하였는데 관련이 없는 다른 부분에 영향을 준다. 수정사항이 관련되지 않은 부분에도 영향을 끼치기 떄문에 관리하는 비용이 커지며 시스템의 credibility 또한 잃는다. |
| 16 | + |
| 17 | +3. Immobility(부동성) |
| 18 | + 부동성이 높다면 재사용하기 위해서 시스템을 분리해서 컴포넌트를 만드는 것이 어렵다. 주로 개발자가 이전에 구현되었던 모듈과 비슷한 기능을 하는 모듈을 만들려고 할 때 문제점을 발견한다. |
| 19 | + |
| 20 | +4. Viscosity(점착성) |
| 21 | + 점착성은 디자인 점착성과 환경 점착성으로 나눌 수 있다. |
| 22 | + |
| 23 | + 시스템에 코드를 추가하는 것보다 핵을 추가하는 것이 더 쉽다면 디자인 점착성이 높다고 할 수 있다. 예를 들어 수정이 필요할 때 다양한 방법으로 수정할 수 있을 것이다. 어떤 것은 디자인을 유지하는 것이고 어떤 것은 그렇지 못할 것이다(핵을 추가). |
| 24 | + |
| 25 | + 환경 점착성은 개발환경이 느리고 효율적이지 못할 때 나타난다. 예를들면 컴파일 시간이 매우 길다면 큰 규모의 수정이 필요하더라도 개발자는 recompile 시간이 길기 때문에 작은 규모의 수정으로 문제를 해결할려고 할 것이다. |
| 26 | + |
| 27 | +위의 design smell은 곧 나쁜 디자인을 의미한다.(스파게티 코드) |
| 28 | + |
| 29 | +# Robert C. Martin's Software design principles(SOLID) |
| 30 | +Robejt C. Martin은 5가지 Software design principles을 정의하였고 앞글자를 따서 SOLID라고 부른다. |
| 31 | + |
| 32 | +## Single Responsibility Principle(SRP) |
| 33 | +A class should have one, and only one, reason to change |
| 34 | + |
| 35 | +클래스는 오직 하나의 이유로 수정이 되어야 한다는 것을 의미한다. |
| 36 | + |
| 37 | +### Example |
| 38 | + |
| 39 | +SRP를 위반하는 예제로 아래 클래스 다이어그램을 보자 |
| 40 | + |
| 41 | + |
| 42 | + |
| 43 | +Register 클래스가 Student 클래스에 dependency를 가지고 있는 모습이다. |
| 44 | +만약 여기서 어떤 클래스가 Student를 다양한 방법으로 정렬을 하고 싶다면 아래와 같이 구현 할 수 있다. |
| 45 | + |
| 46 | + |
| 47 | + |
| 48 | +하지만 Register 클래스는 어떠한 변경도 일어나야하지 않지만 Student 클래스가 바뀌어서 Register 클래스가 영향을 받는다. 정렬을 위한 변경이 관련없는 Reigster 클래스에 영향을 끼쳤기 때문에 SRP를 위반한다. |
| 49 | + |
| 50 | + |
| 51 | + |
| 52 | +위의 그림은 SRP 위반을 해결하기 위한 클래스 다이어그램이다. 각각의 정렬 방식을 가진 클래스를 새로 생성하고 Client는 새로 생긴 클래스를 호출한다. |
| 53 | + |
| 54 | +### 관련 측정 항목 |
| 55 | +SRP는 같은 목적으로 responsibility를 가지는 cohesion과 관련이 깊다. |
| 56 | + |
| 57 | +## Open Closed Principle(OCP) |
| 58 | +Software entities (classes, modules, functions, etc) should be open for extension but closed for modification |
| 59 | + |
| 60 | +자신의 확장에는 열려있고 주변의 변화에는 닫혀 있어야 하는 것을 의미한다. |
| 61 | + |
| 62 | +### Example |
| 63 | + |
| 64 | + |
| 65 | +```java |
| 66 | +void incAll(Employee[] emps) { |
| 67 | + for (int i=0; i<emps.size(); i++) { |
| 68 | + if(emps[i].empType == FACULTY) |
| 69 | + incFacultySalary((FACULTY)emps[i]) |
| 70 | + else if(emps[i].empType == STAFF) |
| 71 | + incStaffSalary((STAFF)emps[i]) |
| 72 | + else if(emps[i].empType == SECRETARY) |
| 73 | + incSecretarySalary((SECRETARY)emps[i]) |
| 74 | + } |
| 75 | +} |
| 76 | +``` |
| 77 | +위의 예제는 아래 문제점을 가지고 있다. |
| 78 | + |
| 79 | +Rigid - 새로운 employee type이 계속 요구된다. |
| 80 | + |
| 81 | +Fragile - 많은 if/lese 구문과 코드를 찾기 어렵다 |
| 82 | + |
| 83 | + |
| 84 | + |
| 85 | +이전에 설명한 문제점을 해결한 클래스 다이어그램이다. |
| 86 | + |
| 87 | +incAll() 함수를 통해서 문제를 해결한 것을 볼 수 있다. |
| 88 | + |
| 89 | +## Liskov Substitution Principle(LSP) |
| 90 | +subtypes must be substitutable for their base types |
| 91 | + |
| 92 | +base 클래스에서 파생된 클래스는 base 클래스를 대체해서 사용할 수 있어야한다. |
| 93 | + |
| 94 | +### Example |
| 95 | +아래는 Java 라이브러리의 Date 클래스이다. |
| 96 | + |
| 97 | + |
| 98 | +```java |
| 99 | +java.util.Date date = new java.util.Date(); |
| 100 | +int dateValue = date.getDate(); // Okay |
| 101 | + |
| 102 | +date = new java.sql.Time(10,10,10); |
| 103 | +dataValue = date.getDate(); // throws IllegalArgumentException |
| 104 | +``` |
| 105 | + |
| 106 | +### Inheritance Vs. Composition |
| 107 | + |
| 108 | + |
| 109 | + |
| 110 | +위의 예제엇 만약 List의 Implemenation을 재사용하게 된다면 inheritance보다 object composition을 사용하는 것을 추천한다. |
| 111 | + |
| 112 | +위에서 Queue 클래스가 List 클래스를 inheritance 한다면 LSP를 위반하게 된다. |
| 113 | + |
| 114 | +## Interface Segregation Principle(ISP) |
| 115 | +Clients should not be forced to depend on methods they do not use |
| 116 | + |
| 117 | +사용하지 않는 메소드에 의존하면 안된다. |
| 118 | + |
| 119 | + |
| 120 | + |
| 121 | +Roast Application은 getName(), getSSN() 메소드만을 사용하고 Account Application은 getInvoice(), postPayment() 메소드만을 사용한다. |
| 122 | + |
| 123 | + |
| 124 | +위 클래스 다이어그램 처럼 클래스에 맞는 interface를 만들어서 제공하면 ISP 문제를 해결할 수 있다. |
| 125 | + |
| 126 | +## Dependency Inversion Principle(DIP) |
| 127 | +high-level modules should not depend on low-level modules. Both should depend on abstractions |
| 128 | + |
| 129 | +자신(high level module)보다 변하기 쉬운 모듈(low level modeul)에 의존해서는 안된다. |
| 130 | + |
| 131 | +### Inversion? |
| 132 | + |
| 133 | + |
| 134 | + |
| 135 | +Program 클래스는 Module 클래스에 dependency를 가지고 있으며 Module 클래스는 Function 클래스에 의존하고 있다. |
| 136 | + |
| 137 | + |
| 138 | + |
| 139 | +Module 클래스를 인터페이스 클래스로 변경을 한 클래스 다이어그램이다. |
| 140 | +이전 그림과 다르게 depenedency가 inversion 된 모습을 볼 수 있다. |
| 141 | + |
| 142 | + |
| 143 | +DIP는 dependency를 inversion 하는 것 뿐 아니라 ownership 또한 inversion 한다. |
0 commit comments