1. Intro (목적)
객체지향 프로그래밍(OOP)의 기본 원칙인 캡슐화, 상속, 다형성, 그리고 추가적으로 객체지향 설계 원칙 중 하나인 개방-폐쇄 원칙(Open-Closed Principle, OCP)에 대해 살펴보고자 한다. 해당 원칙들을 코드의 재사용성, 유지보수성, 확장성을 높이는 데 중요한 역할을 한다. 하지만 이렇게 말로만 들으면 추상적이고 와닿지 않으니 해당 원칙들을 직접 체감하기 위해 온라인 패션 스타일링 서비스라는 상황을 설정하여 구현해보고자 한다.
2. 상황 설정 : 온라인 패션 스타일링 서비스
개요 : 사용자의 취향과 요구에 맞춰 개인화된 패션 스타일링을 제공하는 온라인 서비스가 있다고 가정하자.
개선 전 :
스타일링 제안(예: 캐주얼 룩, 비즈니스 룩, 이브닝 룩)마다 클래스를 따로 만들어, 공통적인 속성(테마, 포함 아이템, 계절)을 중복해서 구현
개선 방향 :
1) 캡슐화
- 캡슐화 원칙을 잘 지키기 위해서는 클래스의 멤버 변수에 대한 직접 접근을 제한하고, private 접근 제어자를 사용하는 것이 바람직하다.
- protected 접근 제어자는 해당 클래스와 동일 패키지 내의 다른 클래스, 그리고 해당 클래스를 상속받는 하위 클래스에서 접근할 수 있게 해주므로, 외부에서 멤버 변수에 직접 접근할 수 있는 가능성이 있다. 이는 캡슐화 원칙에 어긋나며, 객체의 상태를 외부에서 예기치 않게 변경할 수 있는 위험이 존재한다.
- 따라서, 멤버 변수를 private으로 선언하고, 필요한 경우 외부에서 이 변수들을 안전하게 접근하거나 수정할 수 있도록 public 메소드(예: getter와 setter)를 제공하는 방법이 캡슐화 원칙을 더 잘 지키는 방법이다. 이렇게 함으로써 데이터의 은닉성과 보호를 강화할 수 있다.
2) 상속
- 'FashionStyling' 이라는 상위 클래스를 만들어 모든 스타일링 제안의 공통적인 속성을 정의한다.
- 각 스타일링 유형은 이 상위 클래스를 상속받아 유형별 특화 기능이나 속성을 추가한다.
- 공통적인 기능과 속성을 상위 클래스에서 관리함으로써 코드의 중복을 줄이고, 유지보수를 용이하게 하며, 새로운 제품이나 서비스 추가 시 기존 코드를 재활용할 수 있는 장점이 있다.
3) 다형성
- FashionStyling 타입의 리스트를 사용하여 다양한 스타일링 옵션을 다형적으로 처리한다.
- 상위 클래스 타입으로 하위 클래스의 인스턴스를 다룰 수 있게 하여, 하나의 타입으로 여러 타입의 객체를 참조하고 사용할 수 있다.
4) OCP 원칙
- 소프트웨어 구성요소(클래스, 모듈, 함수 등)는 확장에는 열려 있어야 하지만, 변경에는 닫혀 있어야 한다. 즉, 기존의 코드를 변경하지 않고도 기능을 확장할 수 있어야 한다.
3. 소스 코드
기본 클래스 : FashionStyling
기본 클래스는 모든 스타일링 옵션들이 공유하는 공통 속성과 메소드를 정의합니다. 이 클래스는 추상 클래스로 선언되어, 구체적인 스타일링 팁을 제공하는 메소드(provideStylingTips)는 각 하위 클래스에서 구현되어야 합니다.
public abstract class FashionStyling {
private String theme;
private String season;
private List<String> includedItems;
public FashionStyling(String theme, String season, List<String> includedItems) {
this.theme = theme;
this.season = season;
this.includedItems = includedItems;
}
// Getter 메소드 추가
public String getTheme() {
return theme;
}
public String getSeason() {
return season;
}
public List<String> getIncludedItems() {
return includedItems;
}
public void displayStylingDetails() {
System.out.println("스타일링 테마: " + getTheme());
System.out.println("적합한 계절: " + getSeason());
System.out.print("포함된 아이템: ");
for (String item : getIncludedItems()) {
System.out.print(item + ", ");
}
System.out.println("\n");
}
//추상메서드 -> 하위 클래스에서 override 해서 구현해야 함
public abstract void provideStylingTips();
}
서브클래스 예시
각 서브클래스는 FashionStyling 클래스를 상속받아 특정 스타일링에 맞는 구체적인 스타일링 팁을 제공한다.
캐주얼 봄 나들이 룩(CasualDayOutLook.java)
import java.util.List;
public class CasualDayOutLook extends FashionStyling {
public CasualDayOutLook(List<String> includedItems) {
super("캐주얼 데이 아웃", "봄", includedItems);
}
@Override
public void displayStylingDetails() {
super.displayStylingDetails();
System.out.println("이 스타일링은 주말 나들이에 적합합니다.");
}
@Override
public void provideStylingTips() {
System.out.println("캐주얼 데이 아웃 스타일링 팁:");
System.out.println("- 레이어드 스타일로 다양하게 연출해 보세요.");
System.out.println("- 편안한 스니커즈를 매치하여 캐주얼한 무드를 완성하세요.");
}
}
비즈니스 미팅 스타일링(BusinessMeetingLook.java)
public class BusinessMeetingLook extends FashionStyling {
public BusinessMeetingLook(List<String> includedItems) {
super("비즈니스 미팅", "가을", includedItems);
}
@Override
public void displayStylingDetails() {
super.displayStylingDetails();
System.out.println("이 스타일링은 중요한 비즈니스 미팅에 적합합니다.");
}
@Override
public void provideStylingTips() {
System.out.println("비즈니스 미팅 스타일링 팁:");
System.out.println("- 정장은 항상 깔끔하게 프레스하세요.");
System.out.println("- 단정한 구두를 선택하여 프로페셔널한 인상을 줄 수 있습니다.");
}
}
이브닝 파티 스타일링(EveningPartyLook.java)
public class EveningPartyLook extends FashionStyling {
public EveningPartyLook(List<String> includedItems) {
super("이브닝 파티", "겨울", includedItems);
}
@Override
public void displayStylingDetails() {
super.displayStylingDetails();
System.out.println("이 스타일링은 겨울철 이브닝 파티에 적합합니다.");
}
@Override
public void provideStylingTips() {
System.out.println("이브닝 파티 스타일링 팁:");
System.out.println("- 우아한 드레스를 선택하여 파티의 주목을 받으세요.");
System.out.println("- 고급스러운 주얼리로 화려함을 더하세요.");
}
}
스타일링 서비스 데모 실행(StylingServiceDemo.java) - 컨트롤러
import java.util.Arrays;
public class StylingServiceDemo {
public static void main(String[] args) {
List<FashionStyling> stylings = Arrays.asList(
new CasualDayOutLook(Arrays.asList("티셔츠", "청바지", "스니커즈")),
new BusinessMeetingLook(Arrays.asList("정장", "구두")),
new EveningPartyLook(Arrays.asList("이브닝 드레스", "주얼리", "킬 힐"))
);
stylings.forEach(styling -> {
styling.displayStylingDetails();
styling.provideStylingTips();
System.out.println("-------------------------------------------");
});
}
}
개방-폐쇄 원칙 (Open-Closed Principle, OCP):
소프트웨어 구성요소(클래스, 모듈, 함수 등)는 확장에는 열려 있어야 하지만, 변경에는 닫혀 있어야 한다. 즉, 기존의 코드를 변경하지 않고도 기능을 확장할 수 있어야 한다.
// 개방-폐쇄 원칙 (OCP) 예시: 새로운 스타일링 옵션 추가 시 FashionStyling 클래스를 변경하지 않고, 새로운 하위 클래스를 추가함으로써 확장
public class SummerBeachLook extends FashionStyling {
public SummerBeachLook(String[] includedItems) {
super("여름 해변 룩", "여름", includedItems);
}
@Override
public void provideStylingTips() {
System.out.println("여름 해변 룩 스타일링 팁:");
// 여름 해변 룩에 맞는 스타일링 팁 제공
}
}
'자바(Java)' 카테고리의 다른 글
엑셀 업로드 기능 구현 (0) | 2024.03.29 |
---|