SOLID 원칙은 객체지향 설계(OOD)의 다섯 가지 기본 원칙을 나타내는 약어입니다. 이 원칙들을 따르면 확장 가능하고 유지보수하기 쉬운 소프트웨어를 개발할 수 있습니다.
1. 단일 책임 원칙(Single Responsibility Principle, SRP)
클래스는 단 하나의 책임(변경의 이유)을 가져야 합니다. 클래스의 책임이 명확하게 정의되어야 하며, 클래스가 변경되는 이유는 오직 하나여야 합니다.
예제 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// SRP 위반 예시
public class Employee {
public void calculatePay() { /* 급여 계산 로직 */ }
public void saveEmployee() { /* 직원 정보 저장 로직 */ }
public void generateReport() { /* 보고서 생성 로직 */ }
}
// SRP 준수 예시
public class EmployeePayCalculator {
public void calculatePay() { /* 급여 계산 로직 */ }
}
public class EmployeeRepository {
public void saveEmployee() { /* 직원 정보 저장 로직 */ }
}
public class EmployeeReportGenerator {
public void generateReport() { /* 보고서 생성 로직 */ }
}
|
cs |
2. 개방-폐쇄 원칙(Open-Closed Principle, OCP)
소프트웨어 개체(클래스, 모듈, 함수 등)는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 합니다. 즉, 기존 코드를 변경하지 않고도 새로운 기능을 추가할 수 있어야 합니다.
예제 코드
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
|
// OCP 위반 예시
public class AreaCalculator {
public double calculateArea(Object shape) {
if (shape instanceof Rectangle) {
Rectangle rectangle = (Rectangle) shape;
return rectangle.getWidth() * rectangle.getHeight();
} else if (shape instanceof Circle) {
Circle circle = (Circle) shape;
return Math.PI * circle.getRadius() * circle.getRadius();
}
// 새로운 도형이 추가될 때마다 이 메소드를 수정해야 함
return 0;
}
}
// OCP 준수 예시
public abstract class Shape {
public abstract double calculateArea();
}
public class Rectangle extends Shape {
// …
@Override
public double calculateArea() {
return width * height;
}
}
public class Circle extends Shape {
// …
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
}
public class AreaCalculator {
public double calculateArea(Shape shape) {
return shape.calculateArea();
}
}
|
cs |
3. 리스코프 치환 원칙(Liskov Substitution Principle, LSP)
상위 타입의 객체를 하위 타입의 객체로 치환해도 프로그램의 정확성이 유지되어야 합니다. 즉, 하위 클래스는 상위 클래스의 계약(메소드 시그니처, 사전/사후 조건 등)을 준수해야 합니다.
예제 코드
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
|
// LSP 위반 예시
public class Rectangle {
protected int width;
protected int height;
// …
}
public class Square extends Rectangle {
@Override
public void setWidth(int width) {
this.width = width;
this.height = width;
}
@Override
public void setHeight(int height) {
this.width = height;
this.height = height;
}
}
// LSP 준수 예시
public abstract class Shape {
public abstract double calculateArea();
}
public class Rectangle extends Shape {
// …
@Override
public double calculateArea() {
return width * height;
}
}
public class Square extends Shape {
// …
@Override
public double calculateArea() {
return side * side;
}
}
|
cs |
4. 인터페이스 분리 원칙(Interface Segregation Principle, ISP)
클라이언트는 사용하지 않는 메소드에 의존하도록 강요받아서는 안 됩니다. 인터페이스는 클라이언트의 요구사항에 맞게 작고 응집도 높은 단위로 분리되어야 합니다.
예제 코드
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
|
// ISP 위반 예시
public interface Printer {
void print();
void scan();
void fax();
}
public class SimplePrinter implements Printer {
@Override
public void print() {
// 인쇄 기능 구현
}
@Override
public void scan() {
throw new UnsupportedOperationException();
}
@Override
public void fax() {
throw new UnsupportedOperationException();
}
}
// ISP 준수 예시
public interface Printer {
void print();
}
public interface Scanner {
void scan();
}
public interface Fax {
void fax();
}
public class SimplePrinter implements Printer {
@Override
public void print() {
// 인쇄 기능 구현
}
}
public class AllInOnePrinter implements Printer, Scanner, Fax {
// …
}
|
cs |
5. 의존 역전 원칙(Dependency Inversion Principle, DIP)
고수준 모듈은 저수준 모듈의 구현에 의존해서는 안 됩니다. 둘 다 추상화에 의존해야 합니다. 추상화는 세부사항에 의존해서는 안 되며, 세부사항은 추상화에 의존해야 합니다.
예제 코드
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
|
// DIP 위반 예시
public class EmailSender {
public void sendEmail(Gmail gmail) {
gmail.send();
}
}
// DIP 준수 예시
public interface EmailService {
void sendEmail(String message);
}
public class EmailSender {
private EmailService emailService;
public EmailSender(EmailService emailService) {
this.emailService = emailService;
}
public void sendEmail(String message) {
emailService.sendEmail(message);
}
}
public class Gmail implements EmailService {
@Override
public void sendEmail(String message) {
// Gmail로 이메일 전송
}
}
|
cs |
SOLID 원칙을 따르면 코드의 가독성, 유지보수성, 확장성이 향상됩니다. 이 원칙들은 서로 상호 보완적이며, 객체지향 설계의 기본 지침으로 활용됩니다. 프로젝트의 요구사항과 상황에 맞게 이 원칙들을 적용하는 것이 중요합니다.