[OOP] 4️⃣ | GoF 디자인 패턴 1

WONNY_LOG·2023년 4월 17일
0

Design Pattern ?

소프트웨어를 설계할 때 특정 맥락에서 자주 발생하는 고질적인 문제들이 또 발생했을 때 재사용할 할 수있는 훌륭한 해결책이다➡️ 코드를 작성할 때 어떤 방법으로 작성하면 좋을지에 대한 문제해결의 방법론이라고 볼수있다"이미 잘 만들어져있는 것을 처음부터 만들 필요가 없다!"

패턴이란?

비슷하거나 동일한 양식 또는 유형들이 반복되어 나타난다는 의미이며, 문제와 해결책도 동일한 유형이나 양식을 통해 쉽게 찾을 수 있다.패턴은 공통언어를 만들어주며 사용되는 요소 사이의 의사 소통을 원활하게 해주는 역할을 한다.

디자인 패턴 구조?

구현 방법이나 언어에 의존적이지 않으며 다양한 상황에 적용할 수 있는 일종의 템플릿과 같다(한 패턴에 변형을 가하거나 어떠한 요구사항을 반영하면 다른 패턴으로 변형되는 특징이 있다)콘테스트 ➡️ 문제 ➡️ 해결

디자인패턴을 사용시 장,단점 ?

  • 장점개발자 간의 원활한 의사소통로직이 명확하고 단순하여 소프트웨어 구조 파악 용이재사용성이 높아 개발 시간 단축설계 변경 요청, 유지보수에 대한 유연한 대처
  • 단점객체지향 설계/구현 위주로 사용된다비교적 초기 투자 비용 크다

아키텍쳐 패턴? vs 디자인 패턴?

  • 아키텍쳐 패턴은 디자인 패턴보다 상위 수준의 설계에 사용된다.
  • 아키텍쳐 패턴이 전체 시스템의 구조를 설계하기 위한 참조 모델이라면, 디자인 패턴은 서브시스템에 속하는 컴포넌트들끼리의 관계를 설계하기 위한 참조 모델이다.

GoF디자인패턴

  • 4명의 사람들이 소프트웨어 개발 영역에서 고안한 디자인 패턴
  • 가장많이 사용되는 디자인 패턴
  • 총 23개의 패턴이 3가지로 분류되어 진다➡️ 생성(5개),구조(7개),행동(11개)

🖐❗️ 앞으로 계속 언급하게 될 클래스(class)와 객체(object) 알고가기클래스 = 객체를 찍어내기 위한 틀, '빵틀' (설계도)객체 = 클래스에서 찍혀나온 결과물, '빵' (결과물)클래스로 객체 즉, 메모리를 찍어 낸것이다.

https://velog.velcdn.com/images%2Fjaewon97%2Fpost%2F67fd8232-5cbb-494b-81ff-f1c30eaf440d%2Fimage.png

디자인패턴 | 목적에 따른 분류

각각의 패턴이 어떤 일을 하기 위한 것인지에 관한 것

1. 생성 패턴 | 생성 과정에 관여

객체 생성에 관련된 패턴화

  • 유연성은 높게, 코드유지는 쉽게, 인스턴스화를 통해 추상화 하는 방법이다
  • 객체의 생성과 조합을 캡슐화해 특정 객체가 생성되거나 변경되어도 프로그램 구조에 영향을 크게 받지 않도록 유연성을 제공한다

2. 구조 패턴 | 객체의 합성에 관여

객체 결합 (구조)에 관련된 패턴화

  • 클래스나 객체를 조합해 더 큰 구조를 만드는 패턴이다
  • 예를 들어 서로 다른 인터페이스를 지닌 2개의 객체를 묶어 단일 인터페이스를 제공하거나 객체들을 서로 묶어 새로운 기능을 제공하는 패턴이다

3. 행동 패턴 | 객체가 상호작용하는 방법이나 관심사를 분리하는 방법에 관여

객체 간 커뮤니케이션 패턴화

  • 객체나 클래스 사이의 알고리즘이나 책임 분배에 관련된 패턴
  • 한 객체가 혼자 수행할 수 없는 작업을 여러 개의 객체로 어떻게 분배하는지,또 그렇게 하면서도 객체 사이의 결합도를 최소화하는 것에 중점을 둔다.

디자인패턴의 종류 ?

1. 생성 패턴

싱글턴(Singleton) 패턴

class의 객체가 해당프로세스에 하나만 만들어지고 그것을 반복해서 사용함

https://velog.velcdn.com/images%2Fjaewon97%2Fpost%2F587c9530-ffa4-4dae-991c-727548f1d8c3%2Fimage.png

  • 여러 객체를 생성하더라도 최초 생성된 객체를 사용한다 ('처음 사용시 초기화')
  • 객체 자체에는 접근이 불가능해서 객체에 대한 접근자(클로저)를 사용하여 실제 객체를 제어할 수 있다
  • 하나만 만들어서 하나만 쓴다! (클래스를 통해 찍어낸 객체만 사용하게 된다) ➡️ 예를 들어, 1. 게임을 만든다고 했을때 게임은 한번만 켜져야한다.2. 앱,웹의 메인화면에서 다크모드 활성화시 다른페이지로 이동해도 동일한 모드가 적용되어 있어야한다. ✔️ javascript언어를 이용해 비공개 상태로 만들어보자
 var singleton = (function() {

    // 비공개 프로퍼티 정의
    var instance;

    // 비공개 메서드 정의
    function init() {

        // singleton 인스턴스 정의
        return {

            // 공개 프로퍼티 정의
            prop: 'value',

            // 공개 메서드 정의
            method: function() {
                return 'hello'
            }

        };

    }

    // 공개 메서드인 getInstance를 정의한 객체, 비공개 프로퍼티 및 메서드에 접근 가능(클로저)
    return {

        getInstance: function() {

            // 인스턴스가 선언이 안되있는경우 인스턴스 생성
            if (!instance) {
                instance = init();
            }

            // 인스턴스가 선언이 되있는 경우 인스턴스 반환
            return instance;

        }
    }
})()

var singleton1 = singleton.getInstance();
console.log(singleton1.method());
var singleton2 = singleton.getInstance();
console.log(singleton1 === singleton2); // true

자바스크립트 ES6 문법 ver.

  let instance = null;
class Singleton{
  constructor(){
    if(instance) return instance;
    this.name = "heecheolman";
    this.age = 24;
    instance = this;
  }
}

var firstSingleton = new Singleton();
var secondSingleton = new Singleton();

console.log(firstSingleton === secondSingleton); // true
console.log(instance === firstSingleton); // true

팩토리 메서드(Factory Method) 패턴

객체 생성 처리를 서브 클래스로 분리해 처리하도록 캡슐화하는 패턴

https://velog.velcdn.com/images%2Fjaewon97%2Fpost%2F22722435-3229-4ffa-b7ba-06f4b901f132%2Fimage.png

  • 공장에서 상품을 생산하듯이, 팩토리 메서드로 비슷한 객체를 찍어내는 동작을 한다
  • 클래스 간의 결합도를 낮춰서 보다 효율적인 코드 제어를 할 수 있다
  • 템플릿 메서드 패턴(Template Method Pattern)에서 파생 되었다(이러한 구조는 상위 클래스에서 로직을 공통화할 수 있다)
    템플릿 메서드 패턴이란?
    상속 관계에 있는 두 클래스에서 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스에서는 추상 메서드를 통해 구체적인 내용을 결정하도록 하는 디자인 패턴이다
    
    상위클래스 = 중요한 뼈대결정 / 추상 메소드의 구현은 하위클래스에게 맡김
     ⬆️
    하위클래스 = 상위클래스에서 상속받은 추상메소드의 구체적인 내용을 결정
  class CafeLatte {
  constructor() {
  this.price = 3000;
  }

  getPrice() {
  return this.price;
  	}
  }

  class CaramelLatte {
  constructor() {
  this.price = 5000;
  }

  getPrice() {
  return this.price;
  	}
  }

  class LatteFactory() {
   // 구체화하는 로직을 묶어 응집도는 높이고, 코드는 깔끔하게
  static create(latteType) {
  if(latteType === 'cafe') {
  return new CafeLatte();
  } else if(latteType === 'caramel') {
  return new CaramelLatte();
  }
  }
  }

  let latte = LatteFactory.create('caramel');
  latte.getPrice(); // 5000

커피종류 추가하기

function coffeeFactory(type) {
let coffee;

if(type === 'latte') coffee = new Latte();
else if(type === 'espresso') coffee = new Espresso();
else if(type === 'cappuccino') coffee = new Cappuccino();
else if(type === 'mocha') coffee = new Mocha();

return coffee;
}

추상 팩토리(Abstract Factory Method)패턴

'객체 집합' 생성 용이구체적인 클래스에 의존하지 않고 서로 관련성이 있거나 독립적인 여러 객체의 집합을 생성하기 위한 인터페이스를 제공한다

https://velog.velcdn.com/images%2Fjaewon97%2Fpost%2F5f98caeb-e67e-4849-b4e0-c8d60e0f9356%2Fimage.png

  • 추상화(Abstact) + 팩토리(Factory)
  • 관련성 있는 여러 종류의 객체를 일관된 방식으로 생성한다
function takeOutCoffee(type) {
  let coffee;

  if(type === 'latte') coffee = new Latte();
  else if(type === 'espresso') coffee = new Espresso();
  else if(type === 'cappuccino') coffee = new Cappuccino();
  else if(type === 'mocha') coffee = new Mocha(); // 새로운 커피가 추가되어 추가한 if 문

  coffee.prepare();
  coffee.make();
  coffee.boxing();

  return coffee;
  }

takeOutCoffee()는 coffee type을 받아서 해당하는 커피를 가공한 후, 완성된 coffee를 리턴해주는 함수이다

효율적인 코드를 위해 로직 속 공통된 부분끼리 묶는다.type에 따라 해당하는 인스턴스를 생성하였다

function takeOutCoffee(type) {
let coffee = coffeeFactory(type);

coffee.prepare();
coffee.make();
coffee.boxing();

return coffee;
}

// 커피 타입을 넘겨주면, 인스턴스를 만들어주는 공장!
function coffeeFactory(type) {
let coffee;

if(type === 'latte') coffee = new Latte();
else if(type === 'espresso') coffee = new Espresso();
else if(type === 'cappuccino') coffee = new Cappuccino();
else if(type === 'mocha') coffee = new Mocha();

return coffee;
}

이렇게 구현하면 새로운 커피가 아무리 추가되어도 takeOutCoffee 함수를 고칠 필요는 없다.

하지만 많은양의 커피가 추가 된다고 가정할 때, 한없이 if문을 추가하기는 비효율적이다

그렇다면 만든다는 행위만 외부에 정의해 두고 사용할 값만 계속 추가한다면!..

class CoffeeFactory {
static createCoffee(factory) {     //coffeeFactory를 factory로 추상화함
return factory.createCoffee(); // 인스턴스를 만드는 행위를 추상화 시킴
}
}

class LatteFactory {
static createCoffee () {
return new Latte();
}
}

class EspressoFactory {
static createCoffee () {
return new Espresso();
}
}

class CappuccinoFactory {
static createCoffee () {
return new Cappuccino();
}
}

// 실행
CoffeeFactory.createCoffee(LatteFactory);
CoffeeFactory.createCoffee(EspressoFactory);
CoffeeFactory.createCoffee(CappuccinoFactory);

행위에 대한 구현은 세부적인 팩토리들을 만들어서 createCoffee()라는 공통적인 메서드를 이용하여 생성하도록 했다.추상 팩토리는 인스턴스의 생성을 서브클래스에게 위임함으로써 의존성을 낮춘다.

function takeOutCoffee(factory) { //추상화 시킨 factory를 인자로 넣어줌
let coffee = coffeeFactory.createCoffee(factory);

coffee.prepare();
coffee.make();
coffee.boxing();

return coffee;
}

스크립트 (구체적인 클래스를 지정하지 않고 인터페이스를 통해 서로 연관되는 객체들을 그룹으로 표현함)

빌더(Builder) 패턴

복잡한 객체(인스턴스)를 단계별로 조립하는 패턴

https://velog.velcdn.com/images%2Fjaewon97%2Fpost%2F2e030d73-1964-4892-8898-9e15f06f0b42%2Fimage.png

  • 큰 유형은 같지만 세부적인 사항이 다를 때 사용한다
  • 로봇을 조립하자! (무언가를 조립해주는 패턴)
  • 복잡한 객체를 생성하는 방법과 표현하는 방법을 정의하는 클래스를 별도로 분리하여,서로 다른 표현이라도 이를 생성할 수 있는 동일한 절차를 제공할 수 있다 스크립트(복합 객체의 생성과 표현을 분리하여 동일한 생성 절차에서도 다른 표현 결과를 만들어낼 수 있다)

프로토타입(Prototype) 패턴

원본 객체를 복사함으로써 객체를 생성함

https://velog.velcdn.com/images%2Fjaewon97%2Fpost%2Ff550c7da-9558-4e9f-b9aa-cea555a66d39%2Fimage.png

  • 다수의 객체 생성시에 발생되는 객체 생성 비용을 효과적으로 줄일 수 있다.

0개의 댓글