믹스인(Mixin)

Rosevillage·2023년 3월 13일
0

자바스크립트는 prototype 기반 언어로 클래스 문법을 지원하지만 다른 언어들의 클래스와는 결이 다르다.
클래스이지만 결국은 prototype chain을 통해서 상속 기능을 구현하기 때문이다.

클래스를 다루는 것은 객체지향 프로그래밍에서 꽤나 중요한 축에 속하는데, 오늘은 객체지향 프로그래밍에서 서로 다른 클래스의 기능(메서드)을 공유 하는 믹스인에 대해서 알아본다.

믹스인

위에서 언급은 간단히 정리하자면 믹스인은 다른 클래스의 기능(메서드)를 가지는 클래스를 의미한다고 정리할 수 있다.

즉, 어떤 클래스의 인스턴스가 자신의 부모가 아닌 다른 클래스의 메서드를 사용할 수 있다는 것이다.

사실 몇몇의 객체지향 프로그래밍 언어는 다중상속을 지원하기에 다중상속이 지원되지 않는 js에서 믹스인을 사용한다는 것은 다중상속을 구현하기 위함이라고도 볼 수 있다.

이렇게만 말하면 너무 어렵게 느껴지고, 과연 어떤 엄청난 기술이 날 기다릴까.. 라는 생각이 들 수 있지만, 결국 하나의 클래스에 원하는 메서드들을 추가해주는 방식으로 이루어진다.

class Animal {
  constructor(say) {
    this.say: say;
  }
}

const Mixin = {
  howSay() {
    console.log(`cat say ${this.say}`)
  }
}

Object.assign(Animal.prototype, Mixin);

const cat = new Animal('meow');
cat.howSay() // cat say meow

클래스 prototype에 객체를 assign 한 것이 끝이다. 너무도 간단하다.

심지어 __proto__ 에 믹스인 하나를 추가하는 것으로 믹스인에 믹스인을 상속하는 것도 가능하다.

class Animal {
  constructor(say) {
    this.say: say;
  }
}

const OtherMixin = {
  sayWhat(sound) {
    console.log(`cat say ${this.say}`)
  }
}

const Mixin = {
  __proto__ : OtherMixin,
  howSay() {
    super.sayWhat(this.say)
  }
}

Object.assign(Animal.prototype, Mixin);

const cat = new Animal('meow');
cat.howSay() // cat say meow

이제 믹스인이 대충 어떤 느낌인지도 알겠는데, 그럼 믹스인을 사용함으로써 얻을 수 있는 장점이 뭐길래 그렇게 어렵게들 설명하는 것일까

wikipedia에서는 믹스인의 장점을 다음과 같이 알려준다.

  1. 여러 클래스가 공용기능들을 사용할 수 있게 하는 다중상속의 메커니즘을 제공하지만, 다중상속의 복잡한 의미론은 제거할 수 있다.
  2. 코드 재사용성 : 믹스인은 프로그래머가 서로 다른 클래스간에 기능을 공유하고자 할 때 유용하다. 동일한 코드를 반복해서 작성하는 대신 공통기능을 믹스인으로 그룹화하고 이 기능을 필요로하는 다른 클래스들에 추가할 수 있다.
  3. 믹스인은 부모클래스의 모든 기능을 상속하지 않고 필요로 하는 기능만 상속하고 사용할 수 있다.

https://ko.wikipedia.org/wiki/믹스인#cite_note-6

일단 당장에 이해가 되는 것은 2번 정도이다.

1번과 3번을 차근차근 알아보자

1. 다중상속의 복잡한 의미론 제거

말이 어렵지 결국 다중상속의 문제를 피한다는 의미이다.
흔히 다이아몬드 문제라 불리는 다중 상속의 모호성 문제인데,

  • A를 상속하는 B와 C
  • B와 C를 다중 상속하는 D
  • 만약 B와 C가 A의 메서드를 자신의 것으로 덮어씌우는 오버라이딩을 했을때
  • D는 어느 부모로부터 메서드를 상속받을까? => 상당히 애매하다

생각만 해도 골이 아파오지만 다행이도 js는 다중상속을 지원하지 않고, js에서 믹스인을 사용하는 방식은 믹스인 객체를 클래스의 prototype에 집어 넣는것이기 때문에 크게 걱정할 필요는 없다.

물론 믹스인 과정을 함수로 구현해서 prototype을 붙여넣을 수도 있다. 이 경우에는 constructor를 명시적으로 고정시켜줘야 한다.

3. 부모 클래스에게서 원하는 기능만 상속

어떻게 원하는 것만 쏙 골라서 상속하지? 만약 클래스 문법과 객체만 사용한다면 간단하지 않을수도 있다. 함수로 작성하면 생각보다 간단하게 해결된다.

function mixin(base, target) {
	for (var property in target) {
		if(target.hasOwnProperty(property) && property!=='bye' ){ //조건문으로 거르는 방법도 있고
			base[property] = target[property];
		}
	}
	return base;
}

function TargetMethods() {};
TargetMethods.prototype = {
  hello() {
    console.log('hello');
  },
  bye() {
    console.log('bye');
  }
};

let Friend = function () {};

mixin(Friend.prototype, TargetMethods.prototype);
mixin(Friend.prototype, {constructor: Friend});

//mixin(Friend.prototype, {
//	bye() {
//     console.log(bye)
//   }
//}); mixin 호출시 원하는 메서드만 객체 형태로 명시할 수도 있다.

let john = new Friend();
john.hello();

결론

믹스인은 다중상속의 다이아몬드 문제를 피하면서, 다중상속을 구현하는 방법이다.

js에서는 prototype 병합으로도 볼 수 있으며, 원하는 메서드를 골라서 상속시킬 수 있다. 또한 클래스의 기능을 확장하는 용도로 사용할 수도 있다.

상당히 장점이 많아 보이지만,

현재 내가 주로 공부하고 있는 react는 함수형 컴포넌트를 주로 사용하고 있기 때문에 적용할 부분이 없고,

만약 mixin을 사용하다가 실수로 기존 클래스의 메서드를 오버라이딩 해버리면 충돌이 일어날 수 있다는 단점을 지니기도 한다.
그래서 사용시에는 메서드의 네이밍에 주의해야 할 필요가 있다.

0개의 댓글