본문 바로가기

자바(Java)

캡슐화, 상속, 다형성 그리고 OCP 원칙

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