SOLID
소스 코드를 가독성 있고 확장을 쉽게 하도록 하는 객체 지향 설계 원칙
SRP
(단일 책임 원칙),OCP
(개방-폐쇄 원칙),LSP
(리스코프 치환 원칙),ISP
(인터페이스 분리 원칙),DIP
(의존관계 역적 원칙)가 있음
"어떠한 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 한다." - 로버트 C. 마틴
// MemberOrder.java
public class MemberOrder {
// 회원 정보
private Long id;
private String name;
private Grade grade;
// 주문 정보
private String itemName;
private int itemPrice;
private int discountPrice;
public MemberOrder(Long id, String name, Grade grade, String, itemName, int itemPrice, int discountPrice) {
this.id = id;
this.name = name;
this.grade = grade;
this.itemName = itemName;
this.itemPrice = itemPrice;
this.discountPrice = discountPrice;
}
public int calculatePrice() {
return itemPrice - discountPrice;
}
// (회원 정보, 주문 정보 필드의 getter/setter 메서드 생략)
}
MemberOrder
클래스는 회원 정보와 회원 별 주문 정보에 대한 것// Member.java
public class Member {
private Long id;
private String name;
private Grade grade;
public Member(Long id, String name, Grade grade) {
this.id = id;
this.name = name;
this.grade = grade;
}
// (getter/setter 메서드 생략)
}
// Order.java
public class Order {
private Long memberId;
private String itemName;
private int itemPrice;
private int discountPrice;
public Order(Long memberId, String itemName, int itemPrice, int discountPrice) {
this.memberId = memberId;
this.itemName = itemName;
this.itemPrice = itemPrice;
this.discountPrice = discountPrice;
}
public int calculatePrice() {
return itemPrice - discountPrice;
}
// (getter/setter 메서드 생략)
}
Member
클래스를 수정Order
클래스를 수정인터페이스
)과 구현(구현 클래스
)을 분리public class DiscountPolicy {
private int discountFixAmount = 1000; // 정액 할인 정책
public int discount(Member membr, int price) { // 정액 할인 정책에 따른 할인 금액 계산
if(member.getGade() == Grade.VIP) {
return discountFixAmount;
} else {
return 0;
}
}
}
DiscountPolicy
클래스는 할인 정책에 따른 할인 금액을 계산하는 역할// DiscountPolicy.java
public interface DiscountPolicy {
int discount(Member member, int price);
}
// FixDiscountPolicy.java
public class FixDiscountPolicy implements DiscountPolicy {
private int discountFixAmount = 1000;
@Override
public int discount(Member member, int price) {
if(member.getGrade() == Grade.VIP) {
return discountFixAmount;
} else {
return 0;
}
}
}
// RateDiscountPolicy.java
public class RateDiscountPolicy implements DiscountPolicy {
private int discountPercent = 10;
@Override
public int discount(Member member, int price) {
if(member.getGrade == Grade.VIP) {
return price * discountPercent / 100;
} else {
return 0;
}
}
}
DiscountPolicy
인터페이스에 할인 정책에 따른 할인 금액을 계산하는 메서드(역할
)를 선언DiscountPolicy
인터페이스를 구현하면 됨// CarRole.java
public interface CarRole {
void drive();
void repair();
}
// CarDriver.java
public class CarDriver implements CarRole {
private String name;
public CarDriver(String name) {
this.name = name;
}
@Override
public void drive() {
System.out.println("자동차 운전자가 운전을 합니다.");
}
@Override
public void repair() {
System.out.println("운전자의 역할이 아닙니다.");
}
// (getter/setter 메서드는 생략)
}
// Mechanic.java
public class Mechanic implements CarRole {
private String name;
public Mechanic(String name) {
this.name = name;
}
@Override
public void drive() {
System.out.println("정비사의 역할이 아닙니다.");
}
@Override
public void repair() {
System.out.println("정비사가 자동차를 정비합니다.");
}
// (getter/setter 메서드는 생략)
}
CarRole
인터페이스에 자동차의 역할을 정의함CarDriver
클래스는 자동차 운전자, Mechanic
클래스는 정비사CarDriver
클래스는 driver()
메서드, Mechanic
클래스는 repair()
메서드를 구현하기 위해 CarRole
인터페이스를 구현해야 함CarDriver
, Mechanic
클래스에서 불필요한 메서드도 오버라이딩해야 하는 문제가 발생CarDriver
, Mechanic
클래스 모두 수정이 필요하므로 ISP를 위반 ! ! !// Drive.java
public interface Drive {
void drive();
}
// Repair.java
public interface Repair {
void repair();
}
// CarDriver.java
public class CarDriver implements Drive {
private String name;
public CarDriver(String name) {
this.name = name;
}
@Override
public void drive() {
System.out.println("자동차 운전자가 운전을 합니다.");
}
// (getter/setter 메서드는 생략)
}
// Mechanic.java
public class Mechanic implements Repair {
private String name;
public Mechanic(String name) {
this.name = name;
}
@Override
public void repair() {
System.out.println("정비사가 자동차를 정비합니다.");
}
// (getter/setter 메서드는 생략)
}
CarRole
인터페이스를 Drive
, Repair
인터페이스로 분리CarDriver
클래스는 Drive
인터페이스를 구현Mechanic
클래스는 Repair
인터페이스를 구현구현 클래스
) 안되고 추상화(인터페이스
)에만 의존해야 함// DiscountPolicy.java
public interface DiscountPolicy {
int discount(Member member, int price);
}
// FixDiscountPolicy.java
public class FixDiscountPolicy implements DiscountPolicy {
private int discountFixAmount = 1000; // 1000원 할인
@Override
public int discount(Member member, int price) {
if(member.getGrade() == Grade.VIP) {
return discountFixAmount;
} else {
return 0;
}
}
}
// OrderServiceImpl.java
public class OrderServiceImpl implements OrderService {
// OrderServiceImpl 클래스(클라이언트 코드)가 DiscountPolicy 인터페이스(추상화)도 의존하면서 FixDiscountPolicy 클래스(구체화)도 의존함
private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
}
클라이언트 코드
)에서 DiscountPolicy
인터페이스(추상화
)와 FixDiscountPolicy
클래스(구체화
)를 의존함OrderServiceImpl
클래스에서 추상화만 의존하도록 수정해야 함// DiscountPolicy.java
public interface DiscountPolicy {
int discount(Member member, int price);
}
// FixDiscountPolicy.java
public class FixDiscountPolicy implements DiscountPolicy {
private int discountFixAmount = 1000; // 1000원 할인
@Override
public int discount(Member member, int price) {
if(member.getGrade() == Grade.VIP) {
return discountFixAmount;
} else {
return 0;
}
}
}
// OrderServiceImpl.java
public class OrderServiceImpl implements OrderService {
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
}
// AppConfig.java
public class AppConfig {
public OrderService orderService() {
return new OrderServiceImpl(discountPolicy());
}
public DiscountPolicy discountPolicy() {
return new FixDiscountPolicy();
}
}
OrderServiceImpl
클래스에서 DiscountPolicy
인터페이스만 의존FixDiscountPolicy
클래스는 외부에서 인스턴스를 생성하여 OrderServiceImple
클래스에 주입 시켜줘야함 -> DI(의존관계 주입) 이라고 부름AppConfig
클래스에서 DI를 수행하도록 하여 DIP 적용 성공 ! ! !
잘 읽어보안네요 덕분에 SOLID에 대해 알게되었읍니다. 정리는 좀 더 하실 필요 있으시네요. 오늘도 무탈하셔요