1. 단일 책임 원칙 (Single Responsibility Principle - SRP)
단일 책임 원칙(SRP, Single Responsibility Principle)은 "클래스는 단 하나의 책임만 가져야 하며, 변경의 이유가 하나여야 한다."는 원칙이다.
즉, 하나의 클래스가 너무 많은 역할을 담당하면 유지보수가 어려워지고, 코드가 변경될 때 예기치 않은 문제가 발생할 가능성이 높아진다. SRP를 준수하면 각 클래스가 하나의 기능만 담당하여 코드의 가독성과 유지보수성이 향상된다.
❌ SRP를 위반한 코드 (잘못된 예시)
🚨 잘못된 설계: Employee 클래스가 너무 많은 역할을 담당
class Employee {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public double getSalary() {
return salary;
}
// 🔴 급여 계산 기능 (책임 1)
public double calculateBonus() {
return salary * 0.1;
}
// 🔴 데이터베이스 저장 기능 (책임 2)
public void saveToDatabase() {
System.out.println(name + "을(를) 데이터베이스에 저장했습니다.");
}
// 🔴 보고서 생성 기능 (책임 3)
public void generateReport() {
System.out.println(name + "의 급여 보고서를 생성했습니다.");
}
}
// 실행 코드
public class Main {
public static void main(String[] args) {
Employee emp = new Employee("홍길동", 5000);
System.out.println("보너스: " + emp.calculateBonus());
emp.saveToDatabase();
emp.generateReport();
}
}
❌ 문제점 (SRP 위반)
- Employee 클래스가 "급여 계산", "데이터베이스 저장", "보고서 생성" 기능을 모두 포함하고 있음. → 책임이 여러 개라서 유지보수가 어려움.
- 한 기능(saveToDatabase())을 수정할 때, 다른 기능(calculateBonus(), generateReport())에 영향을 미칠 가능성이 있음.
- 급여 계산 로직이 변경될 경우, Employee 클래스를 직접 수정해야 하므로 OCP(Open-Closed Principle)도 위반할 가능성이 큼.
- 데이터 저장 방식이 변경되면 Employee 클래스를 수정해야 함. (ex: MySQL → MongoDB 변경)
✅ SRP를 준수한 코드 (올바른 예시)
🛠 개선된 설계: 역할을 분리하여 각각의 클래스가 단일 책임을 가짐
// 직원 정보 관리 (급여 계산 책임 없음)
class Employee {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public double getSalary() {
return salary;
}
public String getName() {
return name;
}
}
// 🔹 급여 계산 기능을 별도의 클래스로 분리
class BonusCalculator {
public double calculateBonus(Employee employee) {
return employee.getSalary() * 0.1;
}
}
// 🔹 데이터 저장 기능을 별도의 클래스로 분리
class EmployeeDatabase {
public void save(Employee employee) {
System.out.println(employee.getName() + "을(를) 데이터베이스에 저장했습니다.");
}
}
// 🔹 보고서 생성 기능을 별도의 클래스로 분리
class EmployeeReport {
public void generateReport(Employee employee) {
System.out.println(employee.getName() + "의 급여 보고서를 생성했습니다.");
}
}
// 실행 코드
public class Main {
public static void main(String[] args) {
Employee emp = new Employee("홍길동", 5000);
BonusCalculator bonusCalculator = new BonusCalculator();
System.out.println("보너스: " + bonusCalculator.calculateBonus(emp));
EmployeeDatabase db = new EmployeeDatabase();
db.save(emp);
EmployeeReport report = new EmployeeReport();
report.generateReport(emp);
}
}
✅ SRP 준수로 개선된 점
- 각 클래스가 단 하나의 책임만 가짐
- Employee → 직원 정보만 저장 (급여, 이름 등)
- BonusCalculator → 급여 보너스 계산
- EmployeeDatabase → 데이터베이스 저장
- EmployeeReport → 보고서 생성
- 변경에 유연함
- 급여 계산 로직이 변경되더라도 Employee 클래스에는 영향을 미치지 않음.
- 데이터 저장 방식(MySQL → MongoDB) 변경 시 EmployeeDatabase 클래스만 수정하면 됨.
- 유지보수가 쉬워짐
- 특정 기능에 대한 코드만 수정하면 되므로 리팩토링 및 버그 수정이 용이함.
🔥 결론
- SRP 위반 코드: Employee 클래스가 너무 많은 책임을 가지고 있음. → 코드가 복잡해지고, 유지보수 및 확장성이 떨어짐.
- SRP 준수 코드: BonusCalculator, EmployeeDatabase, EmployeeReport 클래스로 역할을 분리하여 각 클래스가 단일 책임을 가짐. → 유지보수성이 좋아지고, 코드가 변경될 때 최소한의 수정만 필요함.
✅ SRP를 준수하면 각 클래스가 하나의 역할만 담당하여 코드가 깔끔하고 유지보수가 쉬워진다! 🚀
2. 개방-폐쇄 원칙 (Open-Closed Principle - OCP)
개방-폐쇄 원칙(OCP, Open-Closed Principle)은 "소프트웨어 구성 요소(클래스, 모듈, 함수 등)는 확장에는 열려 있어야 하지만, 변경에는 닫혀 있어야 한다."는 원칙이다.
즉, 기존 코드를 수정하지 않고 새로운 기능을 추가할 수 있도록 설계해야 한다. 이를 위해 인터페이스나 추상 클래스를 활용하여 유연성을 확보하는 것이 핵심이다.
❌ OCP를 위반한 코드 (잘못된 예시)
🚨 잘못된 설계: calculateBonus()가 새로운 직원 유형 추가 시 수정이 필요함
class Employee {
protected String name;
protected double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public double getSalary() {
return salary;
}
}
// 급여 보너스를 계산하는 클래스
class BonusCalculator {
public double calculateBonus(Employee employee, String employeeType) {
if (employeeType.equals("Regular")) {
return employee.getSalary() * 0.1; // 정규직 보너스: 10%
} else if (employeeType.equals("Manager")) {
return employee.getSalary() * 0.2; // 매니저 보너스: 20%
}
return 0; // 기본값
}
}
public class Main {
public static void main(String[] args) {
Employee emp1 = new Employee("홍길동", 5000);
BonusCalculator calculator = new BonusCalculator();
System.out.println("홍길동의 보너스: " + calculator.calculateBonus(emp1, "Regular"));
}
}
❌ 문제점 (OCP 위반)
- 새로운 직원 유형 추가 시 calculateBonus()를 직접 수정해야 함 → 예: Intern(인턴)의 보너스를 추가하려면 BonusCalculator를 수정해야 함.
- 변경에 닫혀 있지 않음 → 기존 코드(calculateBonus())를 수정하면 새로운 버그가 발생할 가능성이 있음.
- 유지보수가 어려움 → if-else 문이 많아질수록 가독성이 떨어지고, 확장성이 낮아짐.
✅ OCP를 준수한 코드 (올바른 예시)
🛠 개선된 설계: 새로운 직원 유형을 추가할 때 기존 코드 수정 없이 확장 가능
// 급여 보너스를 계산하는 인터페이스
interface BonusPolicy {
double calculateBonus(Employee employee);
}
// 직원의 기본 클래스
class Employee {
protected String name;
protected double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public double getSalary() {
return salary;
}
}
// 정규직 보너스 정책 (10%)
class RegularBonusPolicy implements BonusPolicy {
@Override
public double calculateBonus(Employee employee) {
return employee.getSalary() * 0.1;
}
}
// 매니저 보너스 정책 (20%)
class ManagerBonusPolicy implements BonusPolicy {
@Override
public double calculateBonus(Employee employee) {
return employee.getSalary() * 0.2;
}
}
// 새로운 직원 유형 추가 (인턴 보너스 정책: 5%)
class InternBonusPolicy implements BonusPolicy {
@Override
public double calculateBonus(Employee employee) {
return employee.getSalary() * 0.05;
}
}
// BonusCalculator 클래스가 특정 직원 유형을 알 필요가 없음 (OCP 준수)
class BonusCalculator {
public double calculateBonus(Employee employee, BonusPolicy policy) {
return policy.calculateBonus(employee);
}
}
// 실행 코드
public class Main {
public static void main(String[] args) {
Employee emp1 = new Employee("홍길동", 5000);
Employee emp2 = new Employee("이순신", 7000);
Employee emp3 = new Employee("유관순", 4000);
BonusCalculator calculator = new BonusCalculator();
System.out.println("홍길동의 보너스: " + calculator.calculateBonus(emp1, new RegularBonusPolicy()));
System.out.println("이순신의 보너스: " + calculator.calculateBonus(emp2, new ManagerBonusPolicy()));
System.out.println("유관순의 보너스: " + calculator.calculateBonus(emp3, new InternBonusPolicy())); // 새로운 유형 추가!
}
}
✅ OCP 준수로 개선된 점
- 새로운 직원 유형(예: 인턴) 추가 시 기존 코드 수정 없이 BonusPolicy 인터페이스를 구현하면 됨
- InternBonusPolicy 클래스를 추가하면 BonusCalculator 코드를 수정하지 않아도 됨.
- 기존 BonusCalculator는 BonusPolicy 인터페이스에만 의존하여 확장 가능.
- 변경에는 닫혀 있고, 확장에는 열려 있음
- calculateBonus() 내부 로직을 수정할 필요 없이 새로운 보너스 정책을 추가할 수 있음.
- if-else 조건문을 제거하여 가독성이 향상됨.
- 유지보수 및 확장성이 뛰어남
- 새로운 정책을 추가할 때 BonusPolicy 인터페이스만 구현하면 되므로 코드 변경이 최소화됨.
- 다양한 보너스 정책을 독립적으로 관리할 수 있음.
🔥 결론
- OCP 위반 코드: calculateBonus() 메서드가 새로운 직원 유형을 추가할 때마다 변경되어야 함. → 변경에 닫혀 있지 않음!
- OCP 준수 코드: BonusPolicy 인터페이스를 통해 보너스 정책을 분리하여, → 새로운 정책을 추가해도 기존 코드를 수정할 필요 없음!
✅ OCP를 준수하면 코드의 확장성이 좋아지고, 변경이 필요할 때 최소한의 수정으로 대응할 수 있는 구조가 된다. 🚀
3. 리스코프 치환 원칙 (Liskov Substitution Principle - LSP)
리스코프 치환 원칙(LSP, Liskov Substitution Principle)은 "자식 클래스는 언제나 부모 클래스를 대체할 수 있어야 한다."는 원칙이다.
즉, 상속받은 하위 클래스는 상위 클래스의 동작을 변경시키지 않고, 일관성 있게 동작해야 한다.
❌ LSP를 위반한 코드 (잘못된 예시)
🚨 잘못된 설계: TemporaryEmployee가 calculateSalary()를 무의미하게 오버라이드
// 상위 클래스: 모든 직원이 공통적으로 가져야 할 속성과 기능 정의
class Employee {
protected String name;
public Employee(String name) {
this.name = name;
}
// 정규직 직원은 월급 계산 가능
public double calculateSalary() {
return 3000; // 기본 월급
}
}
// 하위 클래스: 계약직 직원 (급여가 없는 경우)
class TemporaryEmployee extends Employee {
public TemporaryEmployee(String name) {
super(name);
}
// 계약직 직원은 급여를 계산하지 않음
@Override
public double calculateSalary() {
throw new UnsupportedOperationException("계약직 직원은 급여를 계산할 수 없습니다!"); // LSP 위반
}
}
// 메인 실행 코드
public class Main {
public static void main(String[] args) {
Employee employee = new Employee("홍길동");
System.out.println(employee.name + "의 급여: " + employee.calculateSalary());
Employee tempEmployee = new TemporaryEmployee("이순신"); // 부모 타입으로 선언
System.out.println(tempEmployee.name + "의 급여: " + tempEmployee.calculateSalary()); // 예외 발생!
}
}
❌ 문제점 (LSP 위반)
- TemporaryEmployee가 Employee를 상속받았지만, calculateSalary()가 정상적으로 동작하지 않음. → Employee를 대체하려고 하니 예외(UnsupportedOperationException)가 발생!
- 상위 클래스(Employee)를 사용하는 코드가 하위 클래스(TemporaryEmployee)에 의해 망가짐 → 다형성(polymorphism)이 깨지고, 부모 클래스를 대체할 수 없음.
✅ LSP를 준수한 코드 (올바른 예시)
🛠 개선된 설계: SalaryEmployee와 NonSalaryEmployee로 분리
// 상위 클래스: 직원의 기본 개념 정의 (급여 계산 기능을 제거)
abstract class Employee {
protected String name;
public Employee(String name) {
this.name = name;
}
}
// 급여를 받는 직원 (정규직, 계약직 등)
class SalaryEmployee extends Employee {
private double salary;
public SalaryEmployee(String name, double salary) {
super(name);
this.salary = salary;
}
public double calculateSalary() {
return salary;
}
}
// 급여가 없는 직원 (인턴, 자원봉사자 등)
class NonSalaryEmployee extends Employee {
public NonSalaryEmployee(String name) {
super(name);
}
}
// 메인 실행 코드
public class Main {
public static void main(String[] args) {
SalaryEmployee regularEmployee = new SalaryEmployee("홍길동", 3000);
System.out.println(regularEmployee.name + "의 급여: " + regularEmployee.calculateSalary());
NonSalaryEmployee intern = new NonSalaryEmployee("이순신"); // 급여 계산 X
System.out.println(intern.name + "은(는) 급여가 없습니다.");
}
}
✅ LSP 준수로 개선된 점
- Employee의 개념을 추상화하여, 급여를 받는 직원(SalaryEmployee)과 급여가 없는 직원(NonSalaryEmployee)을 분리함.
- 하위 클래스가 부모 클래스를 정상적으로 대체 가능
- SalaryEmployee는 calculateSalary()를 제공하고,
- NonSalaryEmployee는 급여 계산 기능이 없는 대신, 예외를 발생시키지 않음.
- 다형성을 유지하면서 안전하게 설계됨
- SalaryEmployee와 NonSalaryEmployee는 각각의 역할에 맞게 동작하여 calculateSalary()가 필요하지 않은 클래스에서 예외가 발생하지 않음.
- 유지보수성이 향상됨.
🔥 결론
- LSP 위반 코드: TemporaryEmployee가 Employee를 상속받았지만, calculateSalary() 메서드를 사용할 수 없음 → 부모 클래스를 대체할 수 없음!
- LSP 준수 코드: 급여를 받는 직원(SalaryEmployee)과 급여가 없는 직원(NonSalaryEmployee)을 분리하여 각각의 역할에 맞는 동작을 유지 → 부모 클래스를 안전하게 대체 가능!
LSP를 준수하면 안전한 상속 설계가 가능해지고, 다형성이 유지되며, 예기치 않은 예외가 발생하는 문제를 방지할 수 있다. 🚀
4. 인터페이스 분리 원칙 (Interface Segregation Principle - ISP)
인터페이스 분리 원칙(ISP)는 "클라이언트는 자신이 사용하지 않는 인터페이스에 의존하면 안 된다"는 원칙이다. 즉, 하나의 커다란 인터페이스보다는 작은 인터페이스로 분리하여 필요한 기능만 구현하도록 설계해야 한다. 이를 통해 코드의 유연성과 유지보수성이 향상된다.
❌ ISP를 준수하지 않은 코드 (잘못된 예시)
// 하나의 인터페이스가 너무 많은 역할을 가지고 있음 (SRP, ISP 위반)
interface Employee {
void work();
void takeBreak();
void requestLeave();
void calculateSalary();
void approveLeave(); // 모든 직원이 이 기능을 가져야 하는가?
}
// 일반 직원 클래스
class RegularEmployee implements Employee {
@Override
public void work() {
System.out.println("일반 직원이 업무를 수행합니다.");
}
@Override
public void takeBreak() {
System.out.println("일반 직원이 휴식을 취합니다.");
}
@Override
public void requestLeave() {
System.out.println("일반 직원이 휴가를 요청합니다.");
}
@Override
public void calculateSalary() {
System.out.println("급여를 계산합니다.");
}
@Override
public void approveLeave() {
// 일반 직원은 휴가를 승인할 수 없음! (ISP 위반)
throw new UnsupportedOperationException("일반 직원은 휴가를 승인할 수 없습니다!");
}
}
// 매니저 클래스
class Manager implements Employee {
@Override
public void work() {
System.out.println("매니저가 업무를 수행합니다.");
}
@Override
public void takeBreak() {
System.out.println("매니저가 휴식을 취합니다.");
}
@Override
public void requestLeave() {
System.out.println("매니저가 휴가를 요청합니다.");
}
@Override
public void calculateSalary() {
System.out.println("급여를 계산합니다.");
}
@Override
public void approveLeave() {
System.out.println("매니저가 휴가를 승인합니다.");
}
}
❌ 문제점 (ISP 위반)
- Employee 인터페이스가 너무 많은 기능을 포함하고 있음.
- 일반 직원(RegularEmployee)은 approveLeave() 기능을 사용할 수 없으므로, 불필요한 메서드를 구현해야 함. 이는 "클라이언트가 사용하지 않는 메서드에 의존하면 안 된다"는 ISP 원칙을 위반함.
- 새로운 역할(예: 인턴)이 추가될 경우 Employee 인터페이스의 불필요한 메서드를 계속 구현해야 하는 문제 발생.
✅ ISP를 준수한 코드 (올바른 예시)
// 업무 관련 인터페이스 (모든 직원이 수행)
interface Workable {
void work();
void takeBreak();
}
// 급여 관련 인터페이스 (정규직 직원만 해당)
interface Payable {
void calculateSalary();
}
// 휴가 요청 인터페이스 (모든 직원이 해당)
interface LeaveRequestable {
void requestLeave();
}
// 휴가 승인 인터페이스 (매니저만 해당)
interface LeaveApprovable {
void approveLeave();
}
// 일반 직원 (정규직)
class RegularEmployee implements Workable, Payable, LeaveRequestable {
@Override
public void work() {
System.out.println("일반 직원이 업무를 수행합니다.");
}
@Override
public void takeBreak() {
System.out.println("일반 직원이 휴식을 취합니다.");
}
@Override
public void requestLeave() {
System.out.println("일반 직원이 휴가를 요청합니다.");
}
@Override
public void calculateSalary() {
System.out.println("급여를 계산합니다.");
}
}
// 매니저 (정규직)
class Manager implements Workable, Payable, LeaveRequestable, LeaveApprovable {
@Override
public void work() {
System.out.println("매니저가 업무를 수행합니다.");
}
@Override
public void takeBreak() {
System.out.println("매니저가 휴식을 취합니다.");
}
@Override
public void requestLeave() {
System.out.println("매니저가 휴가를 요청합니다.");
}
@Override
public void calculateSalary() {
System.out.println("급여를 계산합니다.");
}
@Override
public void approveLeave() {
System.out.println("매니저가 휴가를 승인합니다.");
}
}
// 인턴 (급여 계산 제외)
class Intern implements Workable, LeaveRequestable {
@Override
public void work() {
System.out.println("인턴이 업무를 수행합니다.");
}
@Override
public void takeBreak() {
System.out.println("인턴이 휴식을 취합니다.");
}
@Override
public void requestLeave() {
System.out.println("인턴이 휴가를 요청합니다.");
}
}
✅ ISP 준수로 개선된 점
- 각 역할별로 인터페이스를 분리하여, 필요한 기능만 구현하도록 만듦.
- RegularEmployee는 approveLeave()를 구현할 필요가 없음.
- 새로운 역할(예: Intern)이 추가될 때, 필요하지 않은 메서드를 구현할 필요가 없음.
- 클래스 간 의존성이 줄어들고, 유지보수성이 향상됨.
🔥 결론
- ISP 위반 코드: 하나의 인터페이스가 너무 많은 기능을 포함하여, 모든 클래스가 불필요한 메서드를 구현해야 하는 문제가 발생.
- ISP 준수 코드: 인터페이스를 역할별로 나누어, 각 클래스가 필요한 기능만 구현하도록 설계 → 유지보수성이 향상되고, 새로운 요구사항 변경이 용이해짐.
이처럼 ISP를 준수하면 "필요한 기능만 구현하는 유연한 설계"가 가능해지며, 불필요한 코드 구현을 줄이고, 확장성이 높아지는 장점이 있다. 🚀
5. 의존 역전 원칙 (Dependency Inversion Principle - DIP)
의존성 역전 원칙(DIP)은 "상위 수준 모듈(High-level Module)이 하위 수준 모듈(Low-level Module)에 직접 의존해서는 안 된다. 둘 다 추상화(인터페이스)에 의존해야 한다."는 원칙이다.
즉, 구체적인 클래스가 아니라 인터페이스나 추상 클래스에 의존하여 유연성을 높여야 한다.
❌ DIP를 위반한 코드 (잘못된 예시)
// EmployeeManager 클래스가 직접 MySQLDatabase에 의존 (강한 결합, DIP 위반)
class MySQLDatabase {
public void save(String employeeName) {
System.out.println(employeeName + " 정보를 MySQL 데이터베이스에 저장했습니다.");
}
}
class EmployeeManager {
private MySQLDatabase database;
public EmployeeManager() {
this.database = new MySQLDatabase(); // 직접 객체 생성 (하드코딩)
}
public void addEmployee(String employeeName) {
database.save(employeeName);
}
}
public class Main {
public static void main(String[] args) {
EmployeeManager manager = new EmployeeManager();
manager.addEmployee("홍길동");
}
}
❌ 문제점 (DIP 위반)
- 강한 결합 (Tight Coupling)
- EmployeeManager 클래스는 MySQLDatabase에 직접 의존하고 있음.
- 데이터베이스가 바뀌면 EmployeeManager도 수정해야 함 (예: PostgreSQLDatabase로 변경 시 코드 수정 필요).
- 확장성 부족
- 데이터베이스 종류를 쉽게 변경할 수 없음.
- 다른 데이터베이스(MySQL → PostgreSQL 등)로 변경할 경우 새로운 클래스를 만들어야 하고, 기존 코드도 수정해야 함.
✅ DIP를 준수한 코드 (올바른 예시)
// 1. 추상화 계층(인터페이스) 생성
interface Database {
void save(String employeeName);
}
// 2. MySQLDatabase 클래스 (인터페이스 구현)
class MySQLDatabase implements Database {
@Override
public void save(String employeeName) {
System.out.println(employeeName + " 정보를 MySQL 데이터베이스에 저장했습니다.");
}
}
// 3. PostgreSQLDatabase 클래스 (새로운 DB 추가 가능)
class PostgreSQLDatabase implements Database {
@Override
public void save(String employeeName) {
System.out.println(employeeName + " 정보를 PostgreSQL 데이터베이스에 저장했습니다.");
}
}
// 4. EmployeeManager 클래스가 구체적인 DB 클래스가 아니라 인터페이스(Database)에 의존 (DIP 준수)
class EmployeeManager {
private Database database;
// 생성자를 통해 의존성 주입 (Dependency Injection)
public EmployeeManager(Database database) {
this.database = database;
}
public void addEmployee(String employeeName) {
database.save(employeeName);
}
}
// 5. Main 클래스에서 원하는 DB 구현체를 주입하여 사용
public class Main {
public static void main(String[] args) {
Database mySQLDatabase = new MySQLDatabase();
EmployeeManager manager1 = new EmployeeManager(mySQLDatabase);
manager1.addEmployee("홍길동");
Database postgreSQLDatabase = new PostgreSQLDatabase();
EmployeeManager manager2 = new EmployeeManager(postgreSQLDatabase);
manager2.addEmployee("이순신");
}
}
✅ DIP 준수로 개선된 점
- 느슨한 결합 (Loose Coupling)
- EmployeeManager는 Database 인터페이스에 의존하므로, 특정 데이터베이스(MySQL, PostgreSQL 등)에 직접 의존하지 않음.
- EmployeeManager 코드를 수정하지 않고도 다양한 데이터베이스를 사용할 수 있음.
- 확장성 증가
- 새로운 데이터베이스(OracleDatabase, MongoDBDatabase 등)를 추가할 때 기존 코드 수정 없이 Database 인터페이스를 구현하기만 하면 됨.
- 의존성 주입 (Dependency Injection) 적용
- 생성자를 통해 의존성을 주입하여 변경이 유연해짐.
- 객체 간의 강한 결합이 사라지고, 유지보수가 용이해짐.
🔥 결론
- DIP 위반 코드: 상위 수준 모듈(EmployeeManager)이 하위 수준 모듈(MySQLDatabase)에 직접 의존 → 강한 결합 발생, 확장 어려움
- DIP 준수 코드: 상위 수준 모듈(EmployeeManager)이 추상화(Database)에 의존 → 유연성과 확장성이 증가하고, 유지보수가 쉬워짐!
DIP를 적용하면 코드의 재사용성이 높아지고, 변경이 필요할 때 최소한의 수정으로 대응할 수 있는 구조가 된다. 🚀
'자바(Java)' 카테고리의 다른 글
Java - equals, hashCode (2) | 2024.11.08 |
---|---|
Java - 엑셀 업로드 후 DB 저장 (0) | 2023.08.25 |
Java - Stream (0) | 2023.08.17 |
Java - 메소드 참조와 Optional 클래스 (0) | 2023.08.11 |
Java - 람다식 (0) | 2023.08.11 |