[디자인패턴] Abstract Factory 패턴

Abstract Factory 패턴

구체적인 클래스에 의존하지 않고 서로 연관되거나 의존적인 객체들의 조합을 만드는 인터페이스를 제공하는 패턴.

싱글턴, 팩토리 메서드 패턴을 사용한다.

추상 팩토리 패턴은 팩토리 메서드 패턴을 좀 더 캡슐화한 방식이라고 볼 수 있다.

서로 관련이 있는 객체들을 통째로 묶어서 팩토리 클래스를 만들고, 이들 팩토리를 조건에 따라 생성하도록 다시 팩토리를 만들어서 객체를 생성하는 패턴

관련성 있는 여러 종류의 객체를 일관된 방식으로 생성하는 경우에 유용하다.

** 여기서 중요한건 TV와 TVFactory 함수(인터페이스)가 인터페이스의 역할을 함으로써 여러 팩토리가 같은 추상화된 같은 인터페이스를 통해서 관리가 가능하다는 것.

즉 밑의 코드는 TvProduct라는 클래스가 여러 상품 팩토리 객체를 통해 만들어진 상품 객체를 이용할 수 있는 코드이다.

function Interface() {
  this.implements = function(obj) {
    var notImplementMethod = [];
    for(var method in this) {
      if(method !== "implements") {
        if(!Object.hasOwnProperty.call(obj.__proto__.method)){
          notImplementsMethod.push(method);
        }
      }
    }

    if(notImplementMethod.length > 0) {
      throw new Error(obj.__proto__.constructor.name + "클래스의" + notImplementMethod.join() + "메서드가 구현되지 않았습니다.")
    }
  }
}

//TV 인터페이스 선언

function TV() {
  if(this.constructor === TV) {
    throw new Error(this.constructor.name + "인터페이스는 객체를 생성할 수 없습니다.")
  }
  return (function(){
    // 인터페이스 정의 메소드
    var method = {
      turnOn: function(){},
      turnOff: function(){},
      volumeUp: function(){},
      volumeDown: function(){},
    };
    interface.call(method);
    return method;
  })();
};

// TV 인터페이스를 구현하여 Samsung TV 클래스 선언

function SamsungTV(model, price) {

  TV().implements(this);

  this.brand = "Samsung";

  this.model = model;

  this.price = price;

}

SamsungTV.prototype.turnOn = function() {

  console.log("[" + this.brand + "(" + this.model + ") TV] turn on");

};

SamsungTV.prototype.turnOff = function() {

  console.log("[" + this.brand + "(" + this.model + ") TV] turn off");

};

SamsungTV.prototype.volumeUp = function() {

  console.log("[" + this.brand + "(" + this.model + ") TV] volumn up");

};

SamsungTV.prototype.volumeDown = function() {

  console.log("[" + this.brand + "(" + this.model + ") TV] volumn Down");

};


// TV 인터페이스를 구현하여 LG TV 클래스 선언

function LgTV(model, price) {

  TV().implements(this);

  this.brand = "LG";

  this.model = model;

  this.price = price;

}

LgTV.prototype.turnOn = function() {

  console.log("[" + this.brand + "(" + this.model + ") TV] turn on");

};

LgTV.prototype.turnOff = function() {

  console.log("[" + this.brand + "(" + this.model + ") TV] turn off");

};

LgTV.prototype.volumeUp = function() {

  console.log("[" + this.brand + "(" + this.model + ") TV] volumn up");

};

LgTV.prototype.volumeDown = function() {

  console.log("[" + this.brand + "(" + this.model + ") TV] volumn Down");

};

// TVFactory 인터페이스 선언

function TVFactory(){

  if (this.constructor === TVFactory){

    throw new Error(this.constructor.name

      + ' 인터페이스는 객체를 생성할 수 없습니다.');

  }

  return (function(){

  // 인터페이스 정의 메서드

  var method = {

    create : function(){},

    setInfo : function(model, price){},

  };

  // 인터페이스의 implements 메서드를 method객체에 이식한다.

  Interface.call(method);

  return method;

})();

};

// TVFactory 인터페이스를 구현하여 SamsungTVFactory 클래스 선언

function SamsungTVFactory(model, price) {

  this.model = model;

  this.price = price;

  TVFactory().implements(this);

}

SamsungTVFactory.prototype.create = function() {

  return new SamsungTV(this.model, this.price);

};

SamsungTVFactory.prototype.setInfo = function(model, price) {

  this.model = model;

  this.price = price;

  return this;

};

​

// TVFactory 인터페이스를 구현하여 SamsungTVFactory 클래스 선언

function LgTVFactory(model, price) {

  this.model = model;

  this.price = price;

  TVFactory().implements(this);

}

LgTVFactory.prototype.create = function() {

  return new LgTV(this.model, this.price);

};

LgTVFactory.prototype.setInfo = function(model, price) {

  this.model = model;

  this.price = price;

  return this;

};

​

// 클라이언트 클래스

var TVProduct = (function(){

  function TVProduct() {}

  TVProduct.prototype.getTV = function(tvFactory) {

    return tvFactory.create();

  }

  return new TVProduct();

})();

​

function test() {

  var samsungTVFactory = new SamsungTVFactory();

  var lgTVFactory = new LgTVFactory();

  var samsungTv = TVProduct.getTV(samsungTVFactory.setInfo("S-001", "1000000"));

  var samsungTv2 = TVProduct.getTV(samsungTVFactory.setInfo("S-002", "1000001"));

  var lgTv = TVProduct.getTV(lgTVFactory.setInfo("L-001", "1000001"));

  var lgTv2 = TVProduct.getTV(lgTVFactory.setInfo("L-002", "1000002"));

  samsungTv.turnOn(); // [Samsung(S-001) TV] turn on

  samsungTv2.turnOn(); // [Samsung(S-002) TV] turn on

  lgTv.turnOn(); // [LG(L-001) TV] turn on

  lgTv2.turnOn(); // [LG(L-002) TV] turn on

}

​

test();


참조:
https://blog.naver.com/PostView.nhn?blogId=mycho&logNo=221843113038&parentCategoryNo=&categoryNo=&viewDate=&isShowPopularPosts=false&from=postList
https://victorydntmd.tistory.com/300
https://gmlwjd9405.github.io/2018/08/08/abstract-factory-pattern.html
https://gmlwjd9405.github.io/2018/08/08/abstract-factory-pattern.html