ネイチャーエンジニアの足あと

ネイチャーエンジニアが経験した、事業・自然・エンジニアリングに関する情報を発信します。

オブジェクト指向のメリットとは?【プログラミング設計に役立つ】

オブジェクト指向って何が良いの?

どうやって役立てれば良いの?

こんな疑問にお答えします。


ネイチャーエンジニアの亀田です。


僕は会社員で8年、フリーランスで2年、エンジニア経験を積んできました。


多くのプログラミング言語に組み込まれている考え方に、「オブジェクト指向」があります。


この考え方はフレームワークなどにもふんだんに使われています。


しかし、その内部のコードを追ったり運用したことがないと、なかなかオブジェクト指向の恩恵を意識しないかもしれません。


かくいう僕も、オブジェクト指向を勉強したのは大学時代ですが、社会人になって何年か実務経験を積むまでは、その本質を理解できていませんでした


オブジェクト指向のメリットはシンプル。


人間にとって分かりやすいから」に尽きます。


でも、このメリットって実際にサービスを出して、運用・保守までやって見ないと気付きづらいのですね。


というわけで今回は、かつての自分のような人に向けて、オブジェクト指向を解説していきます。




 

オブジェクト指向とは

f:id:kkamedev:20180807161123j:plain
オブジェクト指向とは、システム構成を人間がイメージしやすい「モノ(=オブジェクト)」に例える考え方です。


具体例で考えて見ます。


複数の商品の金額を入力すると、それらの合計金額に消費税(8%)を計算して表示する機能」を作るとします。


オブジェクト指向でない「手続き型」の考え方と比較してみましょう。


■ 手続き型の場合

  1. 複数の商品の金額を足し合わせる
  2. 1.の結果に消費税(0.08)を掛ける
  3. 2.の結果を表示する


というように、処理単位で考えて実装します。


■ オブジェクト指向の場合
まず処理をする「モノ」を考えます。


  1. 商品の金額を足してくれる役割のモノ(名前:TotalValueCaluculator)
  2. 消費税を計算してくれる役割のモノ(名前:TaxCaluculator)
  3. 結果を表示してくれる役割のモノ(名前:ResultPrinter)
  4. 1~3.に支持する役割のモノ(名前:CalculateManager)


このように、プログラミングの世界の中にそれぞれ役割を持った登場人物を配置します。


4. CalculateManager が 1〜3. に順番にお願いね、と仕事をしてもらう感じ。


手続き型、オブジェクト指向どちらでも、実際に実装する計算処理は同じです。


オブジェクト指向で何が違うかというと、それぞれの処理を「誰がやるか」を定義することです。


これの良いのは、設計思想や構成を他の人に説明しやすいこと。


手続き型の場合は細かい処理の順番を覚えないと説明できませんが、オブジェクト指向では登場人物の定義を抑えればOKです。


具体的に、「消費税を計算する処理」で人に説明する場合で比較して見ましょう。

■ 手続き型の場合
「商品の金額を足した後にやってる処理だよ」


■ オブジェクト指向の場合
「TaxCaluculatorがやってる処理だよ」


どうでしょう?


オブジェクト指向では、処理の流れを知ってなくても良いし、オブジェクト指向の方が正確に伝えられてますよね。


多分、手続き型の場合の方がコードは短く書けます


でも「人に伝えやすいか」という点を考えると、オブジェクト指向はとても優秀な考え方なのです。

オブジェクト指向で出てくる用語

f:id:kkamedev:20180808153024j:plain
オブジェクト指向型の言語では、普段耳慣れない考え方がいくつかあります。


  • 継承
  • ポリモーフィズム
  • カプセル化


など。


これらを理解すると、オブジェクト指向をより活用することができます。


すなわち、システムがより理解しやすい設計になります


1つ例として、「継承」について説明します。


「モノ」の多くには、定義が階層化されています。


例えば「トノサマバッタ」の階層はこんな感じ。


動物 → 昆虫 → バッタ → トノサマバッタ


昆虫の分類については、以下の記事で紹介しています↓


合わせて読みたい

虫や鳥の名前の識別に役立つ生物分類の知識。分類階級と活用方法を紹介


これらはどう定義されているかというと、「共通の特徴」で定義されています。


最上位の「動物」には、一番ゆるい共通項があり、「昆虫」や「バッタ」には、それよりも細かい共通項があります。


この概念をシステム設計にも応用しているのが「継承」なんですね。


バッタ」は「昆虫」の特徴を持っていて、「昆虫」は「動物」の特徴を持っています。


例えば、「脚が6本」という特徴は、「昆虫」を継承しているオブジェクトはみんな持っているということです。


なぜこの概念を取り入れているかというと、「モノ」単位でシステム設計した時に、処理の共通化でよく使われるからです。


この特徴はオブジェクト指向の共通の考え方なので、この考え方を使ったシステム設計は人にスムーズに伝えられるようになります。

システム設計が伝えやすくなると何が良いの?

f:id:kkamedev:20180712161414j:plain
オブジェクト指向に限らず、システム設計のメリットは「運用コスト削減ができるから」です。


  • 新しい人が入って来た時の学習コストが下がる
  • 設計思想が伝わりやすいので、バグが混入しにくくなる
  • 開発スピードが上がる(定義通りに実装されていれば色々と拡張・修正しやすい)


といったメリットがあります。


オブジェクト指向ならではのメリットを1つ紹介します。


仕様変更が発生した時の例です。


最初の解説で使った以下の例で考えます。

複数の商品の金額を入力すると、それらの合計金額に消費税(8%)を計算して表示する機能」を作る。


■ 手続き型の場合
1. 複数の商品の金額を足し合わせる
2. 1.の結果に消費税(0.08)を掛ける
3. 2.の結果を表示する


■ オブジェクト指向の場合
1. 商品の金額を足してくれる役割のモノ(名前:TotalValueCaluculator)
2. 消費税を計算してくれる役割のモノ(名前:TaxCaluculator)
3. 結果を表示してくれる役割のモノ(名前:ResultPrinter)
4. 1~3.に支持する役割のモノ(名前:CalculateManager)


例えば、税率が変わって消費税が10%になったら、設計はどう修正したら良いでしょうか?


手続き型の場合、


  • 処理の流れを把握して、消費税を掛けているところを見つけて修正
  • 0.08(また定義名)でコードを検索して修正


といった修正になります。


しかしオブジェクト指向の場合は、消費税に関する処理は「TaxCaluculator」が行なっていることは明白です。


なので、わざわざコードを最初から読み込んだり検索する必要はなく、TaxCaluculator内の処理だけ見れば良いことになります。


またありえるのは、消費税処理が今の機能をもとに関数化されていて、関数名が「Multiply8Percent()」みたいになっていた場合


こうなっていた場合は、関数名を変更し、その呼び出し箇所も修正する必要が出てきます


極端な例ですが、上記のようなパターンは良くあります。


これは「役割」ではなくて「処理」でネーミングするから起きてしまうのですね。


このように、役割を定義することで「影響範囲」を絞り込む効果があるのも、オブジェクト指向のメリットです。


オブジェクト指向をうまく使うと、開発スピードが上がり、バグが入り込む可能性も下がるのが分かると思います。

オブジェクト指向のデメリット

f:id:kkamedev:20181011211042p:plain
では、「オブジェクト指向は無敵なのか?」というとそういうわけでもありません。


以下のようなデメリットがあります。

1. 設計が難しい
2. 冗長化しやすい


1. 設計が難しい

オブジェクト指向の設計は、高いレベルが必要とされます


なぜなら、


  • 要件(仕様、将来的な拡張予測)の正確な理解
  • オブジェクトの最適に定義する論理的な思考
  • プロジェクト事情の考慮


が必要になるからです。


「プロジェクト事情の考慮」とは、マネジメントの問題が絡んでいて、


  • 開発中に要件自体がブレることもある
  • 一般的な定義とプロジェクト内の定義が異なる
  • そもそもプロジェクト内の定義が明確にされていない


などもあり、メリット解説で例を挙げたようなネーミングの問題については、定義がされていないから処理ベースでネーミングしてしまう、という事情もあると思います。


なので場合によって、設計者は要件定義や言葉の交通整理をしなくてはいけないのです。


これは経験の浅い人には難しく、知識だけでなくある程度経験も必要になります。

2. 冗長化しやすい

冗長化とは、同じ処理が複数箇所で記述されるような「無駄」「非効率」な実装のこと。


ClassAとClassBがそれぞれ同じ処理を書いてる、などです。


一方、オブジェクト指向でない場合は、クラスの定義などの縛りはあまりないので、同じ処理があれば関数などで共通化しやすいです。


でも、このような処理があちこちのクラスにあると運用しづらくなるので、回避したいところです。


そこで、DI(Dependency Injection)といった技術などで処理を部品化したりして、冗長化を避ける方法があります。


ただ、これがうまくプロジェクトに組み込めれば良いのですが、注意点もあります。


基礎の思想を超えた技術は、チーム内の知識レベルよってうまく扱えず、逆にコードが複雑化することがあるからです。


そうすると設計は混乱し、依存が多くなったり統一性がなくなって、理解しづらいコードになります


僕の今までの経験で、最新技術が好きな人が組み込んだものの、他の人が使いこなせなかったり理解できずにカオスなコードになっているパターンもよく見てきました。


1人プロジェクトだったり、同レベルの人たちだけのプロジェクトであれば問題ないと思いますが、プロジェクトには多くの人が関わっているものです。


もし扱いの難しい技術を組み込む場合は、メンバーが使えるように共有・布教したり、場合によっては他の技術を検討する必要があると思います。

おわりに

・オブジェクト指向のメリット
・オブジェクト指向で出てくる用語
・オブジェクト指向のデメリット


についてお伝えしました。


これらは座学で分かった気になってもいざやってみると難しいものです。


勉強したことは実践して経験してみて身に付くものだと思います。


さらに日々新しい技術も出てきて、僕も常に勉強しています。


使いやすい技術はうまく身に付けて、快適なプログラミングを目指しましょう。


プログラム設計自体のメリットは以下の記事で書いていますので、ぜひご覧ください。


合わせて読みたい

プログラム設計は何のためにするのか?【有効な設計パターンも紹介】


では、また。