절차적 프로그래밍을 사용한 FizzBuzz

나는 최근에 FizzBuzz 문제를 Open/Closed Principle로 해결하는 것을 목표로 하는 FizzBuzz에 대한 기사를 보았습니다.

여기에서 기사를 탐색할 수 있습니다.

문제는 절차적 프로그래밍 패러다임으로 인해 프로그래머가 잘못된 코드를 작성하게 하는 경우가 많습니다. 그런 다음 OOP와 몇 가지 원칙이 구출됩니다.

내 생각에 여기의 문제는 프로그래밍 패러다임의 유형이 아니라 우리와 관련이 있습니다. 개발자.

그래서 나는 우리가 절차적 프로그래밍으로도 "실제"유지보수 가능한 코드를 작성할 수 있다는 것을 증명하기 위해 이 포스트를 쓰기로 결정했습니다.

저는 JavaScript(ES5)를 사용할 것이지만 그 위에 더미 클래스 없이 독립 실행형 함수를 작성할 수 있는 거의 모든 언어를 작성할 수 있습니다. :)

요구 사항



1에서 n까지의 숫자 목록이 주어집니다.
숫자가 3의 배수이면 Fizz로 대체해야 합니다.
숫자가 5의 배수이면 Buzz로 바꿔야 합니다.
숫자가 3으로 나눌 수 있고 5로 나눌 때 FizzBuzz로 대체해야 합니다.

구현



우리의 흐름은 간단합니다. 우리는 명령적인 방법으로 시작할 것입니다. 패턴을 보면 유용한 기능으로 일반화하고 분리합니다.

따라서 labelDivisibleNumbers라는 간단한 함수로 시작하겠습니다.

fizzBuzz가 포함된 이름으로 지정하지 않은 이유는 무엇입니까?

우리는 그것을 할 수 있지만 여기서 우리가 하는 것은 실제로 숫자를 레이블로 바꾸는 것입니다.

대부분의 경우 가능하면 더 일반적인 이름으로 시작하는 것이 좋습니다.

function labelDivisibleNumbers(options) {
  for (var n = options.start; n < options.end; n++) {

   if (n % 3 === 0 && n % 5 === 0) {
      console.log("FizzBuzz");
      continue;
    }

    if (n % 3 === 0) {
      console.log("Fizz");
      continue;
    }

    if (n % 5 === 0) {
      console.log("Buzz");
      continue;
    }

    console.log(n);
  }
}

다음과 같이 호출할 수 있습니다.

labelDivisibleNumbers({start: 1, end: 100});
startend를 옵션으로 제공하여 시작 및 종료에 대한 요구 사항이 변경되는 경우 더 이상 리팩토링할 필요가 없습니다.

여기서 요점은 항상 하드 코딩을 피하는 것이 좋습니다.

이제 여기에 집중하자.

for (var n = options.start; n < options.end + 1; n++) { 
}

이것은 일반적으로 범위 함수로 알려져 있습니다. 그럼 만들어 봅시다.

function range(options, callback) {
  for (let number = options.start; number < options.end; number++) {
    callback(number);
  }
}

두 번째 매개변수가 콜백인 forEach와 유사하게 만들면 원하는 모든 작업을 수행할 수 있습니다.

따라서 이 기능을 모듈로 만들고 필요한 경우 프로젝트의 다른 부분에서 사용하거나 npm 등에 게시할 수 있습니다.

좋아, 좋아! 이제 콜백 섹션에 집중할 수 있습니다.

function labelDivisibleNumbers(options) {
  range(options, function(n) {

    if (n % 3 == 0 && n % 5 == 0) {
      console.log("FizzBuzz");
      return;
    }

    if (n % 3 == 0) {
      console.log("Fizz");
      return;
    }

    if (n % 5 == 0) {
      console.log("Buzz");
      return;
    }

    console.log(n);
  })
}

당신이 알고 있는지 모르겠지만 우리는 n % x == 0 섹션을 많이 사용합니다.

이것도 참으로 흔한 일이다. 함수로도 만들어보자.

function divisibleBy(dividend, divisor) {
  return dividend % divisor === 0;
}

따라서 n % x == 0을 divisibleBy로 바꿀 수 있습니다.

function labelDivisibleNumbers(options) {
  range(options, function(n) {

    if (divisibleBy(n, 3) && divisibleBy(n, 5)) {
      console.log("FizzBuzz");
      return;
    }

    if (divisibleBy(n, 3)) {
      console.log("Fizz");
      return;
    }

    if (divisibleBy(n, 5)) {
      console.log("Buzz");
      return;
    }

    console.log(n);
  })
}

이제 우리는 console.log("FizzBuzz")에 집중할 수 있습니다. number의 레이블 표현 목록이 있는 함수에 number를 제공하면 굉장할까요?

divisibleBy(n, 5) => 버즈
divisibleBy(n, 3) => 피즈

그 의미
5 => 버즈
3 => 피즈

우리의 데이터는 JS에서 이와 같을 수 있습니다.

var list = [
  {
    divisor: 3,
    label: "Fizz",
  },
  {
    divisor: 5,
    label: "Buzz"
  }
];

따라서 우리가 필요한 것은 목록과 숫자를 입력하고 연결된 레이블을 출력하는 것입니다.

위의 목록이 주어지면 n이 15인 경우 FizzBuzz가 예상됩니다.

여기서 우리는 실제로 감소가 필요합니다. JS에는 내장형 reduce 메소드가 있지만 간단한 for 루프를 사용하여 자체 reduce 함수를 만들어 진행 상황을 더 잘 이해할 수 있도록 합시다.

function reduce(array, callback, accumulator, start) {
  for (var i = 0; i < array.length; i++) {
    accumulator = accumulator == undefined ? start : accumulator;
    accumulator = callback(accumulator, array[i], i, array)
  }
  return accumulator;
}

모든 레이블을 하나의 단일 문자열로 연결해 보겠습니다.

reduce(list, function(acc, curr){
    return acc + curr.label 
}, '')

이것은 훌륭한 시작이지만 제공된 번호에 따라 레이블을 지정하고 싶습니다.

따라서 숫자가 목록의 제수로 나눌 수 있는 경우 연결해야 합니다.

function getLabel(list, n) {
  return reduce(
    list,
    function (acc, curr) {
      return divisibleBy(n, curr.divisor)
      ? acc + curr.label
      : acc;
    },
    ""
  );
}

지금까지 한 모든 작업을 마무리하려면:

function labelDivisibleNumbers(options, list) {
  range(options, function (n) {
   console.log(getLabel(list, n) || n);
  });
}

요구 사항 업데이트



클라이언트로서 현재 구현에 레이블이 있는 새 번호를 추가하고 싶습니다.

숫자가 7로 ​​나누어 떨어지면 Bazz로 대체해야 합니다.
숫자가 5로 나눌 수 있고 7로 나누어 떨어지면 BuzzBazz로 대체해야 합니다.
숫자가 3으로 나뉘고 7로 나누어 떨어지면 FizzBazz로 대체해야 합니다.

우리가 해야 할 일은 Bazz를 해당 번호로 목록에 추가하는 것입니다.

var list = [
  {
    divisor: 3,
    label: "Fizz",
  },
  {
    divisor: 5,
    label: "Buzz",
  },
  {
    divisor: 7,
    label: "Bazz",
  }
];

아직 개선의 여지가 있지만 적시에 물건을 제공하려면 어딘가에 멈춰야 합니다.

즐기 셨으면 좋겠습니다 :)

좋은 웹페이지 즐겨찾기