# 03-09. 기능 편애


# ✋ Intro

  • 프로그램을 모듈화할 때는 코드를 여러 영역으로 나눈 뒤 영역 안에서 이뤄지는 상호작용은 최대한 늘리고 영역 사이에서 이뤄지는 상호작용은 최소로 줄이는 데 주력한다.
  • 기능 편애는 흔히 어떤 함수가 자기가 속한 모듈의 함수나 데이터보다 다른 모듈의 함수나 데이터와 상호작용할 일이 더 많을 때 풍기는 냄새다.
  • 특정 함수가 데이터와 가까이 있고 싶어할 때는 '함수 옮기기' 기법으로 데이터 근처로 옮겨주면 된다.
  • 만약 어디로 옮길지가 명확하게 드러나지 않을 때는 가장 많은 데이터를 포함한 모듈로 옮기면 된다.
    • '함수 추출하기' 기법으로 함수를 여러 조각으로 나눈 후 각각을 적합한 모듈로 옮기면 더 쉽게 해결되는 경우도 많다.

# ➕ 전략 패턴(Strategy Pattern)

동일 계열의 알고리즘들을 정의하고, 각 알고리즘을 캡슐화하며, 이 알고리즘들을 해당 계열 안에서 상호교체가 가능하도록 만든다.

알고리즘을 사용하는 클라이언트와 상관없이 독립적으로 알고리즘을 다양하게 변경할 수 있게 한다.

  • 하나의 클래스가 많은 행동들을 정의하고, 이런 행동들이 그 클래스의 연산 안에서 복잡한 다중 조건문의 모습을 취할 때, 많은 조건문보다는 행동 각각을 전략(Strategy) 클래스로 만들고, 동적으로 행동의 변경이 필요한 경우 **전략(Strategy)**을 바꾸어 주는 것으로 알고리즘을 다양하게 변경할 수 있게 해주는 패턴이다.
function Fedex() {
  this.calculate = package => {
    // fedex calculations
    return 2.45
  }
}

function UPS(){
  this.calculate = package => {
    // ups calculations
    return 1.56
  }
}

function USPS(){
  this.calculate = package => {
    // usps calculations
    return 4.5
  }
}

const fedex = new Fedex()
const ups = new UPS()
const usps = new USPS()

const package = {
  from : "Lee",
  to: "John",
  weight: 4.6
}

function Shipping() {
  this.company;
  this.setStrategy = (company) => {
    this.company = company
  }
  this.calculate = (package) => {
    return this.company.calculate(package)
  }
}

// 같은 매개변수를 주었지만 콘솔에 출력되는 객체에 따라 달라진다..
const shipping = new Shipping()

// fedex 객체가 사용된다.
shipping.setStrategy(fedex)
console.log(shipping.calculate(package)) // => 2.45

// 전략이 바뀌어 ups 객체가 사용된다.
shipping.setStrategy(ups) // Change Strategy
console.log(shipping.calculate(package)) // => 1.56

// 전략이 또 바뀌어 usps 객체가 사용된다.
shipping.setStrategy(usps) // Change Strategy
console.log(shipping.calculate(package)) // => 4.5

// 코드 출처 : https://nwlee.app/posts/javascript-design-pattern/

📖 Reference

  • https://devnest.tistory.com/3

# ➕ 방문자 패턴(Visitor Pattern)

  • **실제 로직을 가지고 있는 객체(Visitor)**가 로직을 **적용할 객체(Element)**를 방문하면서 실행하는 패턴이다.
  • 즉, 로직과 구조를 분리하는 패턴이라고 볼 수 있다. 로직과 구조가 분리되면 구조를 수정하지 않고도 새로운 동작을 기존 객체 구조에 추가할 수 있다.
  • 객체 내 값에 접근하기 위해 방문자 함수를 사용한다. 객체 구조와 메소드를 분리하는 패턴이다.
  • 객체에 직접 접근하는 것을 막을 수 있고 객체 내 연산을 추가하는 것도 가능하다.
function Employee(name, salary){
  this.name = name;
  this.salary = salary;
}

Employee.prototype = {
  getSalary: function(){
    return this.salary
  },
  setSalary: function($){
    this.salary = $;
  },
  accept: function(visitorFunction){
    visitorFunction(this)
  }
}

const lee = new Employee("lee", 1000)
console.log(lee.getSalary()) // 1000

// Employee 객체를 매개변수로 받아서 객체의 메소드를 실행한다.
// 객체 내 프로퍼티의 값을 안전하게 변경할 수 있다.
function ExtraSalary(employee){
  employee.setSalary(employee.getSalary() * 2)
}

lee.accept(ExtraSalary)
console.log(lee.getSalary()) // 2000

📖 Reference

  • https://thecodinglog.github.io/design/2019/10/29/visitor-pattern.html
  • https://nwlee.app/posts/javascript-design-pattern/