君は心理学者なのか?

大学時代に心理学を専攻しなぜかプログラマになった、サイコ(心理学)プログラマかろてんの雑記。

本当にオブジェクト指向を使う必要があるのか?

タイトルについて

すみません、煽りました。

いきさつ

オブジェクト指向で設計した時と、

オブジェクト指向を使わなかった時について、

「単純にコード量だけで」比較してみます。

その上で、オブジェクト指向の利点について再度考えてみます。

つくるもの

  • 1秒間に1, 数字がカウントアップされる
  • カウントアップされるたびに、2で割ったあまりと3で割ったあまりが表示される

f:id:karoten512:20180727001417g:plain

コード

NOTオブジェクト指向でかく

const view1Input = document.getElementById("view1Input");
const view2Input = document.getElementById("view2Input");
const view3Input = document.getElementById("view3Input");

var count = 0;
const countUp = () => {
  count++;
  view1Input.value = count % 2;
  view2Input.value = count % 3;
  view3Input.value = count;
};
setInterval(countUp, 1000);

オブジェクト指向で設計して書く

  • input要素の書き換え…Viewクラス
  • カウンター値保持...Modelクラス
  • 処理開始...Mainクラス

という簡単な責務で考えます。 そしてとりあえずobserverパターンで実装します。

すると。

class ViewModCounter {
  constructor(el, model) {
    this.inputEl = el;
    this.model = model;
    this.mod = 1;
  }
  setMod(num) {
    this.mod = num;
  }
  render() {
    this.inputEl.value = this.model.count % this.mod;
  }
}

class ViewCounter {
  constructor(el, model) {
    this.inputEl = el;
    // viewはmodelに依存している
    this.model = model;
  }
  render() {
    this.inputEl.value = this.model.count;
  }
}

class Model {
  constructor(count) {
    this.count = count;
    this.listeners = [];
  }
  setCount(count) {
    this.count = count;
    this.notify();
  }
  addListener(listener) {
    this.listeners.push(listener);
  }
  notify() {
    this.listeners.forEach((listener, index, listeners) => {
      listener.render();
    });
  }
}

class Main {
  constructor() {
    this.model = new Model(1);

    const view1Input = document.getElementById("view1Input");
    const view2Input = document.getElementById("view2Input");
    const view3Input = document.getElementById("view3Input");

    let view1 = new ViewModCounter(view1Input, this.model);
    view1.setMod(2);
    let view2 = new ViewModCounter(view2Input, this.model);
    view2.setMod(3);
    let viewCounter = new ViewCounter(view3Input, this.model);

    this.model.addListener(view1);
    this.model.addListener(view2);
    this.model.addListener(viewCounter);
  }
  run() {
    const model = this.model;
    let sec = 0;
    setInterval(() => {
      sec++;
      model.setCount(sec);
    }, 1000);
  }
}

const main = new Main();
main.run();

めっちゃ増えた

記述量だけみると、オブジェクト指向で設計するほうが大変です。

※ もちろん要件によっては記述量が逆転することもありえます

じゃあいつオブジェクト指向設計を使うのか

個人的には、

  • 要件が複雑になった時
  • 扱うモノが増えた時

この時、オブジェクト指向設計じゃないとかなり苦しむな、と感じています。 あとは保守のときですね。きちんと設計しないと一つの修正がいろんなところに飛んだりします。

注意

オブジェクト指向設計とはクラス化することではありません。

あくまでも、オブジェクト指向は手段で、

目的は「実装時にいかに楽に、そして保守時にいかに楽になれるか」というところにあります。

それを意識せずにただただクラス化するだけだと、

逆に辛くなることだって起こりえます。

(辛くなったことがある)

そこらへんの話がこの本にかいてあります(もっかい読みたい)

https://www.amazon.co.jp/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E8%A8%AD%E8%A8%88%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-Ruby%E3%81%A7%E3%82%8F%E3%81%8B%E3%82%8B-%E9%80%B2%E5%8C%96%E3%81%97%E3%81%A4%E3%81%A5%E3%81%91%E3%82%8B%E6%9F%94%E8%BB%9F%E3%81%AA%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E8%82%B2%E3%81%A6%E6%96%B9-Sandi-Metz/dp/477418361X