SOLID
1. 단일 책임 원칙(SRP; Single Responsibility Principle)
- 클래스는 단 하나의 책임만을 가져야 한다. 즉 클래스는 변경의 이유가 하나뿐이어야함.
- 예) 'User' 클래스 => 클래스는 사용자 정보를 관리하는 책임만 가져야 한다. 이메일을 보내는 기능은 'EmailService'와 같은 다른 클래스로 분리시켜야 한다.
public class User {
private String name;
private String email;
// 생성자, getter, setter 등
}
public class EmailService {
public void sendEmail(User user, String message) {
// 이메일 전송 로직
}
}
2. 개방 폐쇄 원칙(OCP; Open Close Principle)
- 소프트웨어 개체는 확장에는 열려 있어야 하지만, 수정에는 닫혀 있어야 한다.
- 즉, 기존 코드를 수정하지 않고도 기능을 확장할 수 있어야 한다.
- 예) 새로운 할인 정책을 추가할 때 기존 'Discount' 클래스를 수정하지 않고, 상속을 통해 확장.
public abstract class Discount {
public abstract double applyDiscount(double price);
}
public class ChristmasDiscount extends Discount {
@Override
public double applyDiscount(double price) {
return price * 0.9; // 10% 할인
}
}
public class NewYearDiscount extends Discount {
@Override
public double applyDiscount(double price) {
return price * 0.8; // 20% 할인
}
}
3. 리스코프 치환의 원칙(LSP; Liscov Substitution Principle)
- 서브타입(상속받은 하위 클래스)는 언제나 자신의 기반 타입(상위 클래스)로 교체될 수 있어야 한다.
- 이는 프로그램의 정확성을 해치지 않고, 객체는 부모 클래스의 인터페이스를 그대로 사용할 수 있어야 함을 의미.
- 예) 'Bird' 클래스를 상속하는 'Sparrow' 클래스는 'Bird' 클래스로 대체해도 동일하게 동작해야한다.
public class Bird {
public void fly() {
System.out.println("Flying...");
}
}
public class Sparrow extends Bird {
@Override
public void fly() {
System.out.println("Sparrow flying...");
}
}
public void letBirdFly(Bird bird) {
bird.fly();
}
public static void main(String[] args) {
Bird bird = new Sparrow();
letBirdFly(bird); // "Sparrow flying..." 출력
}
4. 인터페이스 분리의 원칙(ISP; Interface Segregation Principle)
- 한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다.
- 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다. 즉, 인터페이스는 구체적인 사용 사례에 맞게 분리되어야 한다.
- 예) 'Printer' 인터페이스가 'Print'와 'Scan'기능을 모두 포함한다면, 두 인터페이스를 분리하여 각각 필요한 기능만 구현
public interface Printer {
void print(Document document);
}
public interface Scanner {
void scan(Document document);
}
public class MultiFunctionPrinter implements Printer, Scanner {
@Override
public void print(Document document) {
// 인쇄 로직
}
@Override
public void scan(Document document) {
// 스캔 로직
}
}
public class SimplePrinter implements Printer {
@Override
public void print(Document document) {
// 인쇄 로직
}
}
5. 의존성 역전 원칙(DIP; Dependency Inversion Principle)
- 실제 사용 관계는 바뀌지 않으며, 추상을 매개로 메시지를 주고받음으로써 관계를 최대한 느슨하게 만드는 원칙
- 고수준 모듈은 저수준 모듈에 의존해서는 안된다. 둘 다 추상화에 의존. 추상화는 구체적인 사항에 의존해서는 안된다.
- 구체적인 사항이 추상화에 의존
- 예) 'UserService'가 직접 'MySQLDatabase'와 같은 구체적인 데이터베이스 구현에 의존하지 않고, 'Database' 인터페이스에 의존하도록 한다.
public interface Database {
void save(User user);
}
public class MySQLDatabase implements Database {
@Override
public void save(User user) {
// MySQL 저장 로직
}
}
public class UserService {
private Database database;
public UserService(Database database) {
this.database = database;
}
public void saveUser(User user) {
database.save(user);
}
}
public class Main {
public static void main(String[] args) {
Database database = new MySQLDatabase();
UserService userService = new UserService(database);
User user = new User("John Doe");
userService.saveUser(user);
}
}
'Java' 카테고리의 다른 글
| Java 기본 - 클래스(배열) (0) | 2024.11.19 |
|---|---|
| Java 기본 - 클래스, 객체, 인스턴스 (0) | 2024.11.11 |
| StringBuilder (0) | 2024.09.12 |
| 객체지향 프로그래밍 - 객체지향 기법 (0) | 2024.05.30 |
| 객체지향 프로그래밍 - 객체 지향 구성요소 (0) | 2024.05.30 |