OCP, Decorator Pattern, Factory Pattern

‍이시현·2023년 10월 27일
0

Design Pattern

목록 보기
2/6

OCP(Open-Closed Principle)

SOLID는 이미 배운 개념이지만 정리하지 않았기 때문에 마침 책에서 OCP가 나와서 정리해본다.
OCP는 클래스는 확장에는 열려있어야하지만 변경에는 닫혀있어야한다는 원칙이다. 쉽게 말하면 기존 코드의 변경없이 새로운 코드만 만들어서 기능을 추가해야한다는 뜻.

데코레이터 패턴

데코레이터 패턴 객체를 감싸고 추가하고 싶은 기능을 데코레이터가 동적으로 더하는 패턴. 기능확장에 유용

예를들어 커피 전문점 서비스가 있을 때 모든 커피는 휘핑크림이나 샷추가와 같은 옵션들이 추가될 수 있다. 이런 상황에서 가능한 모든 종류에 대해 클래스를 만드는 것은 너무 비효율적이다. 이 때 사용할 수 있는 패턴이 데코레이터 패턴이다.

데코레이터 패턴은 상속과 구성을 동시에 사용한다. 먼저 제일 기본이 되는 Component라는 추상 클래스를 정의하고 필요한 기능을 명시한다. 그 뒤 Decorator는 인터페이스 혹은 추상클래스로 만들고 이 때 Component 클래스를 상속받으면서 동시에 Component 변수를 멤버로 가진다.(Composition) 이 때 Component에서 추상 메소드로 선언되지 않은 메소드도 추상메소드로 만들 수 있다. 휘핑이나 샷 같은 것을 Decorator 클래스를 상속받아 구현한다.(ConcreteDecorator)
블랙커피나 에스프레소와 같은 데코레이터가 아닌 클래스들은 Component 클래스를 상속받아 구현한다. (ConcreteComponent)

여기까지 보았을 때 Decorator를 상속받아 구현된 ConcreteDecorator들과 ConcreteComponent은 서로 Component의 메소드를 공통으로 가지고 있기 때문에 결과적으로 기능이 동일하지만 유일한 차이점은 Decorator는 멤버변수로 Component 클래스 변수를 가지고 있다는 것이다. 그렇기 때문에 ConcreteDecorator들은 그 안에 Component를 상속 받은 모든 클래스를 가질 수 있다. 이 때 중요한 것은 자기자신도 Component를 상속받았기 때문에 ConcreteDecorator끼리도 포함이 가능하다.

데코레이터 패턴의 주의점
추상 데코레이터 클래스(추상 구성요소)의 확장이 많은 코드에는 해당 패턴이 적합하지만 실제 Base 추상클래스를 상속받아 만든 일반 클래스(구상구성요소)를 기반으로 뭔가 기능이 많이 추가될 가능성이 있을 땐 사용해도 별로다.

팩토리 패턴

어떤 클래스 안에서 여러 종류의 인스턴스를 만들어야할 때 인스턴스 만드는 부분을 따로 빼서(책에선 캡슐화라고 표현하고 있음) 처리하는 패턴

팩토리: 객체 생성을 처리하는 클래스

팩토리 패턴에는 Factory Method Pattern, Abstract Factory Pattern이 존재한다.

책에선 피자가게에서 피자를 만들 때 여러 종류의 피자를 만들 수 있어야하는데 피자의 종류는 다양하고 피자를 굽고 자르고 박스에 담는 과정은 전부 동일하다는 상황을 예시로 들고있다.

두 패턴을 공부하기 전에 먼저 Simple Factory의 대해 알아보자

Simple Factory
피자(인스턴스)를 만드는 Factory 클래스를 만든다. 피자가게 클래스의 생성자에서 해당 Factory를 받아오고 피자가게 메소드에서 피자 생성 부분은 해당 클래스의 인스턴스가 맡는다.

Factory Method Pattern
Simple Factory는 클래스 바깥에서 Factory 클래스를 만든 뒤 주입되지만 Factory Method Pattern은 Creator 클래스(예시에서 피자가게 클래스)에 인스턴스를 만드는 메소드를 추상 메소드로 선언하고 Factory는 Creator 클래스를 상속받아 구현된다. 그리고 Factory는 실제 Product 추상 클래스(예시에서 피자 클래스)를 상속받은 클래스(시카고 치즈피자 같은 클래스)를 인스턴스화 시켜 Creator에게 돌려준다. 즉, Creator에서 실제 인스턴스를 만드는 것은 Creator의 서브클래스인 Factory가 하는 것이다.

정적메소드 -> 인스턴스를 만들지 않아도 사용가능 but 서브클래스를 만들어서 해당 메소드 행동 변경 불가능

DIP
추상화된 것에 의존하게 만들고 구상 클래스에 의존하지 않게 만든다.

위 예시를 보면 이해가 쉽다. 본래 Pizza 클래스가 없고 PizzaStore는 모든 종류의 피자에 대해위에서 아래로 전부 화살표가 있었지만 Pizza라는 추상 클래스를 만들고 PizzaStore가 생성자에서 Pizza 타입을 인자로 받으면서 PizzaStore는 단 하나의 Pizza 추상 클래스에만 의존할 수 있게 된 것이다.

Abstract Factory Pattern
추상 팩토리 패턴은 약간 Strategy Pattern와 비슷한 느낌의 패턴이다. Creator를 상속받아 Factory를 구성하는 방식을 버리고 Factory만을 위한 인터페이스(Abstract Factory)를 따로 만든 뒤 그것을 상속받아 Factory 클래스를 만든다. 그리고 클라이언트 (피자가게)는 Abstract Factory를 지역변수로 선언해 새로운 인스턴스를 만들 때 다형성을 이용해 원하는 Factory를 사용하는 것이다.

팩토리 메소드 패턴과 추상 팩토리 패턴의 차이
팩토리 메소드 패턴은 상속을 통해 서브클래스를 만들어 그 서브 클래스가 인스턴스를 만들고 추상 팩토리 패턴은 클래스 안에 인터페이스를 멤버변수로(즉 composition)으로 가져 그 인터페이스를 상속 받은 서브 클래스에서 만들어진다.

profile
알고리즘과 머신러닝에 관심이 있는 평범한 공대생입니다!

0개의 댓글