티스토리 뷰
728x90
SOLID란 무엇인가?
객체 지향 프로그래밍에서 SOLID는 소프트웨어 설계의 이해, 개발, 유지보수를 향상시키기 위한 다섯 가지 설계 원칙의 약어입니다.
이 원칙들을 적용하면 버그 감소, 코드 품질 향상, 더 체계적인 코드 생산, 결합도 감소, 리팩토링 개선, 코드 재사용 촉진 등의 효과를 볼 수 있습니다.
SOLID 원칙 깊게 살펴보기
1. 단일 책임 원칙 (SRP: Single Responsibility Principle)
핵심: 한 클래스는 하나의, 오직 하나의 변경 이유만 가져야 한다.
왜 중요한가?
- 클래스의 응집도 향상
- 유지보수 용이성 증가
- 다른 클래스와의 결합도 감소
예시:
// 잘못된 예
public class ProfileManager {
public boolean authenticateUser(String username, String password) {
// 인증 로직
}
public UserProfile showUserProfile(String username) {
// 사용자 프로필 표시 로직
}
public UserProfile updateUserProfile(String username) {
// 사용자 프로필 업데이트 로직
}
public void setUserPermissions(String username) {
// 권한 설정 로직
}
}
// 개선된 예
public class AuthenticationManager {
public boolean authenticateUser(String username, String password) {
// 인증 로직
}
}
public class UserProfileManager {
public UserProfile showUserProfile(String username) {
// 사용자 프로필 표시 로직
}
public UserProfile updateUserProfile(String username) {
// 사용자 프로필 업데이트 로직
}
}
public class PermissionManager {
public void setUserPermissions(String username) {
// 권한 설정 로직
}
}
2. 개방-폐쇄 원칙 (OCP: Open-Closed Principle)
핵심: 객체나 개체는 확장에는 열려 있어야 하지만, 수정에는 닫혀 있어야 한다.
장점:
- 기존 코드 수정 없이 새로운 기능 추가 가능
- 코드의 유연성과 재사용성 향상
- 시스템 안정성 개선
예시:
// OCP를 적용하기 전
public class Circle {
public double radius;
}
public class Square {
public double side;
}
public class AreaCalculator {
public double totalArea(Object[] shapes) {
double area = 0;
for (Object shape : shapes) {
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
area += Math.PI * circle.radius * circle.radius;
} else if (shape instanceof Square) {
Square square = (Square) shape;
area += square.side * square.side;
}
}
return area;
}
}
// OCP를 적용한 후
public interface Shape {
double area();
}
public class Circle implements Shape {
public double radius;
@Override
public double area() {
return Math.PI * radius * radius;
}
}
public class Square implements Shape {
public double side;
@Override
public double area() {
return side * side;
}
}
public class AreaCalculator {
public double totalArea(Shape[] shapes) {
double area = 0;
for (Shape shape : shapes) {
area += shape.area();
}
return area;
}
}
3. 리스코프 치환 원칙 (LSP: Liskov Substitution Principle)
핵심: 파생 클래스는 기본 클래스를 대체할 수 있어야 한다.
중요성:
- 다형성과 확장성의 올바른 사용 보장
- 예측 가능한 코드 동작 유지
- 코드 재사용성 증가
예시:
class Person {
public String speakName() {
return "I am a person!";
}
}
class Child extends Person {
@Override
public String speakName() {
return "I am a child!";
}
}
public class Main {
public static void printName(Person person) {
System.out.println(person.speakName());
}
public static void main(String[] args) {
Person person = new Person();
Child child = new Child();
printName(person); // 출력: I am a person!
printName(child); // 출력: I am a child!
}
}
4. 인터페이스 분리 원칙 (ISP: Interface Segregation Principle)
핵심: 클래스는 사용하지 않는 인터페이스를 구현하도록 강제되어서는 안 된다.
장점:
- 불필요한 의존성 제거
- 인터페이스의 응집도 향상
- 코드의 유연성과 재사용성 증가
예시:
// ISP를 위반한 예
interface Book {
void read();
void download();
}
class OnlineBook implements Book {
public void read() {
// 읽기 로직
}
public void download() {
// 다운로드 로직
}
}
class PhysicalBook implements Book {
public void read() {
// 읽기 로직
}
public void download() {
// 물리적 책에는 의미 없는 메서드
throw new UnsupportedOperationException();
}
}
// ISP를 적용한 예
interface Readable {
void read();
}
interface Downloadable {
void download();
}
class OnlineBook implements Readable, Downloadable {
public void read() {
// 읽기 로직
}
public void download() {
// 다운로드 로직
}
}
class PhysicalBook implements Readable {
public void read() {
// 읽기 로직
}
}
5. 의존관계 역전 원칙 (DIP: Dependency Inversion Principle)
핵심: 추상화에 의존해야 하며, 구체화에 의존하면 안 된다.
상위 모듈은 하위 모듈에 의존해서는 안 된다. 둘 다 추상화에 의존해야 한다.
추상화는 세부 사항에 의존해서는 안 된다. 세부사항이 추상화에 의존해야 한다.
예시:
// DIP를 적용하기 전
class MySQLDatabase {
public String getUserData(int id) {
// MySQL 데이터베이스에서 사용자 데이터를 가져오는 로직
}
}
class UserService {
private MySQLDatabase database;
public UserService() {
this.database = new MySQLDatabase();
}
public String getUser(int id) {
return this.database.getUserData(id);
}
}
// DIP를 적용한 후
interface Database {
String getUserData(int id);
}
class MySQLDatabase implements Database {
public String getUserData(int id) {
// MySQL 데이터베이스에서 사용자 데이터를 가져오는 로직
}
}
class PostgreSQLDatabase implements Database {
public String getUserData(int id) {
// PostgreSQL 데이터베이스에서 사용자 데이터를 가져오는 로직
}
}
class UserService {
private Database database;
public UserService(Database database) {
this.database = database;
}
public String getUser(int id) {
return this.database.getUserData(id);
}
}
결론
SOLID 원칙은 객체 지향 프로그래밍에서 깔끔하고 유지보수가 쉬운 코드를 작성하기 위한 강력한 가이드라인입니다. 이 원칙들을 이해하고 적용함으로써, 우리는 더 나은 소프트웨어 설계와 개발을 할 수 있습니다. 물론 실제 상황에서는 이 원칙들을 완벽하게 적용하기 어려울 수 있지만, 이를 지향점으로 삼고 노력한다면 분명 더 좋은 코드를 작성할 수 있을 것입니다.
참고 블로그
https://dev.to/lukeskw/solid-principles-theyre-rock-solid-for-good-reason-31hn
728x90
'개발 언어 > 기타 웹개발 지식' 카테고리의 다른 글
URL에서 화면까지: 브라우저의 특급 웹페이지 배달 서비스 (0) | 2024.08.15 |
---|---|
CORS 완벽 가이드: 웹 개발자를 위한 상세 설명서 (0) | 2024.08.15 |
Git 커밋 마스터하기: 효과적인 버전 관리의 비밀 (0) | 2024.08.14 |
로드 밸런싱 알고리즘의 상세 분석과 실제 적용 사례 (0) | 2024.08.14 |
소켓 프로그래밍의 세계: 레스토랑 주방에서 배우는 네트워크 통신의 비밀 (상세편) (0) | 2024.08.14 |
댓글