kgneng2 / blokg

blog
MIT License
0 stars 0 forks source link

design pattern in javascript #27

Open kgneng2 opened 4 years ago

kgneng2 commented 4 years ago

GoF 디자인 패턴 종류

image

개인적으로 주로 생성, 행위패턴을 사용 abstract factory, builder, singleton, strategy, template etc..

Singleton Pattern

적용 전

class Kafka {
  constructor(topic) {
    this.topic = topic;

    try {
      const client = new kafka.KafkaClient(producerConfig);
      this.producer = new HighLevelProducer(client);
      this.consumerGroup = new ConsumerGroup(consumerGroupOptions, [topic, "jy_test2"]);

    } catch (err) {
      log.error(`${this.topic} :: Error from Kafka Ready : ${err}`);
      return process.exit(1);
    }
  }

  publish(value) {
    this.producer.send(
      [
        {
          topic: this.topic,
          messages: new KeyedMessage(null, Buffer.from(value)),
        },
      ],
      (err, data) => {
        err && log.error(`error while kafka producing :: ${err}`);
      },
    );
  }

  subscribe(callbackFunc) {
    this.consumerGroup.on('message', data => {
        console.log(data)
    });
  }
}

export default Kafka;

적용 후


- 같은 객체가 리턴되는지 확인
```javascript
function republishTest() {
  const a = producer();
  const b = producer();

  const d = new Kafka("jy_test")
  const e = new Kafka("jy_test2")

  setTimeout(() => {
    console.log(a === b); //true
    console.log(d === e); //false
  }, 3000);
}

ES6+ 에서 어떻게 사용할까?

object literal 을 이용한 방법

const UserStore = { add: item => _data.push(item), get: id => _data.find(d => d.id === id) }

Object.freeze(UserStore); export default UserStore;


### ES6 Classes
- 좀더 be 와 같은 방식으로 

class UserStore { constructor(){ if(!UserStore.instance){ this._data = []; UserStore.instance = this; }

return UserStore.instance; }

//rest is the same code as preceding example

}

const instance = new UserStore(); Object.freeze(instance);

export default instance;


- instance 를 export 해서 쓰는데, 클래스 자체를 export 하지 않았기 때문에 밖에서 new UserStore 진행시 ERROR 발생  (TypeError: _UserStore.default is not a constructor) 

## Template method pattern
- 알고리즘 뼈대를 만들고 세부사항(특정단계)은 각 세부 클래스들이 진행하도록 한다. 
- javascript의 경우에는 약간의 편법이 필요하다..
- typescript의 경우에는 abstract를 지원하기 때문에 보다 편하게 가능하다.
- 개인적으로 factory pattern과 같이 사용함. (concreateClass가 많아짐에 따라서, 생성한다)

### abstractClass

abstract class ABSTRACT_CLASS { runAlgorithm() { this.step1() this.step2() this.step3() } abstract step1(): void; abstract step2(): void; abstract step3(): void; }


### concreateClass 

class MyBehaviour extends ABSTRACT_CLASS { step1() { log("My step 1") } } step2() { log("My step 2") } step3() { log("My step 3") } } //...


### client

const my = new MyBehaviour() my.runAlgorithm()

//My step 1 //My step 2 //My step 3


### 적용 예제
- typescript : https://oss.navercorp.com/travel/travel-api-workspace/pull/507/files
- javascript : https://oss.navercorp.com/travel/sent/tree/develop/src/job

## Builder Pattern
- 맴버변수가 많아 모았다가, 생성하는 패턴. 

```javascript
export class ClearanceSaleSummary {
  constructor(builder) {
    this.recommendList = builder.recommendList;
    this.provinceList = builder.provinceList;
    this.quickList = builder.quickList;
  }

  static get Builder() {
    class Builder {
      addRecommendList(recommendList) {
        this.recommendList = recommendList;
        return this;
      }
      addProvinceList(provinceList) {
        this.provinceList = provinceList;
        return this;
      }
      addQuickList(quickList) {
        this.quickList = quickList;
        return this;
      }

      build() {
        return new ClearanceSaleSummary(this);
      }
    }

    return Builder;
  }
}

--- 
// client
const clearanceSale = new ClearanceSaleSummary.Builder()
  .addRecommendList([ ])
  .addProvinceList([])
  .addQuickList([])
  .build()

reference

kgneng2 commented 4 years ago

일반적인 singleton https://www.tutorialspoint.com/design_pattern/singleton_pattern.htm