質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

デバッグ

デバッグはプログラムのバグや欠陥を検知し、開発中のバグを取り除く為のプロセスを指します。

Q&A

解決済

5回答

14475閲覧

オブジェクト指向のソースコードは、処理を追いにくくなるものですか?

i50

総合スコア227

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

デバッグ

デバッグはプログラムのバグや欠陥を検知し、開発中のバグを取り除く為のプロセスを指します。

10グッド

15クリップ

投稿2016/04/11 01:11

10

15

現在、オブジェクト指向を勉強中なのですが、
タイトルのような疑問にあたりました。

私の理解しているオブジェクト指向の考え方で、サンプルのプログラムを書いてみました。
(そもそもその理解がおかしいということでしたら、指摘いただけると幸いです)
fugaと表示したり、ランダムでhageと表示されるプログラムです。

php

1//表示してよいか判断する機能。 2interface IDecideToPrint { 3 public function canPrint(); 4} 5 6//表示する機能。 7interface IPrint { 8 public function doPrint(); 9} 10 11//指定されたパーセンテージの確率で表示される。 12class AtRateOfPercentage implements IDecideToPrint { 13 private $_percent; 14 function __construct($percent){ 15 $this->_percent = $percent; 16 } 17 public function canPrint(){ 18 return (rand(1, 100) <= $this->_percent); 19 } 20} 21 22//hageと表示する。 23class PrintHage implements IPrint { 24 public function doPrint(){ 25 print 'hoge'; 26 } 27} 28 29//指定された文字を表示する。 30class PrintParam implements IPrint { 31 private $_str; 32 function __construct($str){ 33 $this->_str = $str; 34 } 35 public function doPrint(){ 36 print $this->_str; 37 } 38} 39 40//判断つきで表示する機能。 41class PrintWithDecision implements IPrint { 42 43 private $_decide; 44 private $_print; 45 46 function __construct(IDecideToPrint $decide, IPrint $print){ 47 $this->_decide = $decide; 48 $this->_print = $print; 49 } 50 51 public function doPrint(){ 52 if($this->_decide->canPrint()){ 53 $this->_print->doPrint(); 54 } 55 } 56} 57 58//様々なIPrintの実装を生成する。 59class PrintFactory { 60 /** 61 * 常にfugaと表示する。 62 * @return IPrint 63 */ 64 public function createAlwaysFuga(){ 65 return new PrintParam('fuga'); 66 } 67 /** 68 * 50%の確率でhageと表示する。 69 * @return IPrint 70 */ 71 public function createRandomHage(){ 72 return new PrintWithDecision( 73 new AtRateOfPercentage(50) 74 ,new PrintHage() 75 ); 76 } 77} 78 79$printFactory = new PrintFactory(); 80$alwaysFuga = $printFactory->createAlwaysFuga(); 81$randomHage = $printFactory->createRandomHage(); 82 83$alwaysFuga->doPrint(); //fugaと表示 84$randomHage->doPrint(); //hageと表示されたりされなかったり(※)

こちらのソースにはバグが有り、hageではなくhogeと表示されています(※)。
そしてこのバグをデバッグするときに、私はおおむね以下の様な順でバグ探しに行きます。

1:doPrint()で問題(※)が起きていて、それはcreateRandomHage()で作られて、さらにそれはPrintFactoryで作られた、とさかのぼる。
2:そこでPrintFactoryのcreateRandomHage()を見に行く。
3:そこで生成されている、PrintWithDecisionを見に行く。
4:PrintWithDecisionを見て、doPrint()の中身はなんだ?と行き詰まる。

(この規模のソースでそれぐらいは覚えとけというツッコミや、単体テストはどうしたというツッコミもあるかと思いますが)
この行き詰まる原因がどうも、オブジェクト指向の本質(?)にあるように思われました。

オブジェクト指向では、基本的にclassはinterfaceに依存するように作られているため、
2→3のように実際のclassを見に行くと、そこはinterfaceでしか書かれおらず、
次に見るべきソース(doPrintの中身)が不明で、行き詰まっていました。

そこで、タイトルの疑問なのですが、
オブジェクト指向のソースコードは、本質的に処理を追いにくくなるものなのでしょうか。
もし、追いにくいものであるとしましたら、何かソースを追うコツとかあるのでしょうか。

よろしくお願いします。

__nt__, hotta, TaroToyotomi, mhashi, Tak1wa, iwamoto_takaaki, musix55, FitD, bonasan, ikuwow👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

ベストアンサー

ポリモーフィズムが利用されているコードの場合は、特に、コードリーディングで処理を追うのは難しいかもしれません。
今回の場合、普通にデバッガを使いそうです。

オブジェクト指向の一般論としては、責任の所在を明確にできるので、
むしろ、どこにバグがあるのか検討がつきやすいと思います。

ただし、今回のように短いソースコードの場合、その恩恵よりも、オブジェクト指向で作成するために記述が冗長になった分、逆に分かりづらいのはありますね。
もともと大規模開発のために生まれた概念ですから。

また、上記のメリットは、
使用するクラスがテストをクリアしていて正しく動作する
という前提がある場合、よりその恩恵を受けることができるでしょう。

投稿2016/04/11 01:37

編集2016/04/11 01:38
Odacchi

総合スコア907

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

i50

2016/04/11 03:52

ご回答ありがとうございます。 デバッガを使われたり、単体テストで責任の所在を明確化していきますと、 オブジェクト指向で書かれたプログラムをコードリーディングで読み進めるスキルは、 あまり使われないスキルとなりそうですね。 そうなりますとデバッグの取っ掛かりとしては、 ソースを追うのではなく、 「hageと表示する機能」をドキュメント等から探すということになりそうですね。 そう考えますと、 オブジェクト指向はその考え方の習得だけではなく デバッガ、phpDoc、PHPUnitと、周辺のものも勉強する必要があるなと感じました。 ありがとうございました!
Odacchi

2016/04/11 11:59 編集

>オブジェクト指向で書かれたプログラムをコードリーディングで読み進めるスキルは、 あまり使われないスキル どちらかというと、読まなければいけない範囲が絞られるのであって、スキルとしては必要ですね。たしかに”量”という意味では減る傾向にあると思います。 >そうなりますとデバッグの取っ掛かりとしては、 ソースを追うのではなく、 「hageと表示する機能」をドキュメント等から探すということになりそうですね。 そうですね。コードリーディングに時間をかける割合が減り、クラスの「構造」や「関連」を把握するのに時間をかける割合が増える感覚があります。 また、IDEなどだと呼び出し階層を表示したりなど、そのメソッドやクラスの階層構造を表示する機能なども充実しているため、ドキュメントを遡る手間は大きく削減できます。
i50

2016/04/12 03:37

>たしかに”量”という意味では減る傾向にあると思います。 量が減るのは助かります! 確かにサンプルのソースも、問題のclassにたどり着けたならば 見るべきは1行だけですものね。 >また、IDEなどだと呼び出し階層を表示したりなど、そのメソッドやクラスの階層構造を表示する機能なども充実しているため、ドキュメントを遡る手間は大きく削減できます。 IDEの特徴とか機能を十分に生かせるような書き方(コードのお作法的な?)、 というのも重要だなと感じました。
guest

0

こんにちは。

全く同じ見た目のコードが呼び出すメソッドが、実は異なるクラスのメソッドってことですね。
これは逆に、異なるクラスのメソッドを同じ手順で呼び出せることでもあり、オブジェクト指向プログラミングの特長の一つである「多様性」ですね。

多様性が使われているインスタンスがどのクラスのインスタンスなのか、静的解析(ソースコードを読む方法)で判別することは事実上無理なので、動的解析(実際に実行する)するため、余分な手間がかかることは事実です。
ですが、多様性を使うべきか、静的解析するため多様性を使わないか、両者のメリット/デメリットを比較すると多様性の方に軍配が上がることが多いように思います。

しかし、多様性を使う必要もないのにわざわざ使って可読性を劣化させているケースも散見します。
それは、間違った「オブジェクト指向プログラミング」ではないかと思います。

投稿2016/04/11 01:31

編集2016/04/11 01:35
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

i50

2016/04/11 03:52

ご回答ありがとうございます。 ソースコードを読むという静的解析が困難で、 動的解析しかないとなりますと、 実際に動かせるテスト環境も用意する必要があると感じました。 多様性を使う使わないの判断基準につきましては、 重要な事と感じましたので、調べてみたり考えてみたりしたいと思います。 ありがとうございました!
guest

0

オブジェクト指向のソースコードは、本質的に処理を追いにくくなるものなのでしょうか。

継承やオーバーライドなど状況によって実行(参照)されるコードが異なるという点では、単純なテキストベースでは追いづらいかもしれません。検索しても複数にヒットするので、ソースをさかのぼって実際にどれが呼ばれるのかを見極めないといけませんからね。
ただ、「本質的」かどうかでいえば違うと思います。ソースの追いにくさは設計やコーディングの問題の方が大きいです。
オブジェクト指向では何らかの関連性によってまとまっていることが多いので、概要を把握したり問題を絞り込んだりする上ではむしろ追いやすいと思います。

もし、追いにくいものであるとしましたら、何かソースを追うコツとかあるのでしょうか。

IDE(統合開発環境)のデバッガーとコード解析機能を利用するのがベストだと思います。私がソースコードの編集でテキストエディタを使いつつもIDEのエディタも併用する理由はそれです。

投稿2016/04/11 02:32

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

i50

2016/04/11 03:53

ご回答ありがとうございます。 オブジェクト指向のソースは、テキストベースで追うのは難しいが、 機能や関連性でまとまる様になるので、機能や関連性で追えば容易になる、 ということですね。 そうなりますと、 いかに機能や関連性でまとまるように、様々なclassを配置整理するかというのは かなり重要のように感じます。 また、IDEの使い方も習熟する必要があると感じました。 オブジェクト指向は、周辺の技術があってこその技術なのですね。 ありがとうございました!
guest

0

なかなか刺激的なタイトルなので、たくさん反応がありそうですね。

手続き型で書いてもオブジェクト指向で書いても、デバッグの難しさは変わらないです。(細かい点をのぞく。)

例として出されたコードはちょっと変なコードです。必要もないのにインターフェイスを多用しています。
インターフェイスは、確かに実際に実行されているクラスを判別するのには手間がかかります。ただし、実装がバラバラなオブジェクトを一つにまとめるにはよい方法です。

例では、doPrintメソッドを呼び出す前に、randを使うという点のみが相違点なので、継承を使うとわかりやすいと思います。というわけで、私が書くならというコードです。(とその前に、そもそもClassを定義しなくてもいいレベルのコードかもしれません。)

PHP

1<?php 2class Printer { 3 private $str; 4 function __construct($str){ 5 $this -> str = $str; 6 } 7 public function print(){ 8 echo $this->str ; 9 echo "\n"; 10 } 11} 12 13//Printerオブジェクトのちょっとだけ変わったオブジェクトなので継承を使う 14class RamdamizePrinter extends Printer{ 15 private $parsent; 16 function __construct($str, $percent){ 17 //そのまま使えるコードは再利用 18 parent::__construct($str); 19 $this->percent = $percent; 20 } 21 public function print(){ 22 if(rand(1, 100) <= $this->percent) { 23 parent::print(); 24 } 25 } 26} 27 28class PrinterFactory { 29 // どのオブジェクトを呼び出すべきかの判断は 30 // 呼び出し元は気にしなくていいようにするのがFactoryの利点 31 public function create($value){ 32 if($value == 'hoge') { 33 return new RamdamizePrinter('hoge', 50); 34 } else { 35 return new printer($value); 36 } 37 } 38} 39 40$arr = array("fuga", "hoge"); 41$printerFactory = new PrinterFactory(); 42 43//同じ変数に入れるなどしないと、多態の意味がない 44foreach ($arr as $value) { 45 $some = $printerFactory->create($value); 46 $some->print(); 47} 48?>

これなら、比較的わかりやすいと思います。

厳しい言い方になりますが、i50さんが指摘している部分は不要なメソッドが多いコードを書いたというだけで、この書き方では手続き型で書いても同じくらい追いづらいです。

また、新しい環境のようにオブジェクト指向の書き方に慣れていないから追いづらいということも大いにあると思います。
インターフェイスのみが多態を行う方法ではないですし、多態のみではオブジェクト指向について判断するには早すぎると思います。

オブジェクト指向プログラミングは、コードのコピペを減らしたり、メソッドの変数を減らしたり、複数のメソッドをまとめたりすることで、コードをわかりやすくまとめることができます。

特にオブジェクト指向でなければ書けないプログラムはないので、適材適所で利用すればいいと思いますし、便利なところで利用するのが習得の早道だと思います。

投稿2016/04/11 03:53

iwamoto_takaaki

総合スコア2883

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

i50

2016/04/11 04:24

ご回答ありがとうございます。 ソースコードまで提示していただきましてありがとうございます! とてもスッキリしていて追いやすいです。 interfaceではなく、classになっていると読みやすいのですね。 適材適所を考えてソースを書くことを注意していきたいと思います。 金づちを持つとすべてが釘に見える、という言葉が思い出されました…。 不慣れのため、サンプルが適切ではなかったなと感じてはおります…。 まず、なんでも抽象に依存させておこう、という意識でした。 ありがとうございました!
iwamoto_takaaki

2016/04/11 07:24

覚えたてのやり方は取り合えず使ってみるという方法は、何かをみにつけるのに良い方法だと思います。 私の場合は、抽象化の範囲は利用する方のコードが、「細かいこと知らんが、これやっといて」ですむように書くことだと考えています。
i50

2016/04/11 09:23

ありがとうございます! 皆様に色々と教えていただけましたので、まずは色々試してみようと思います! 抽象化の「細かいことは知らない」、というのは大事と感じています。
guest

0

本質的に処理を追いにくくなるものなのでしょうか

オブジェクトの本質は、ロジックを責務で細分化し、ファイルやディレクトリで分けて管理することにあります。
システムが肥大化した結果、1万行を超えるようなものに成長した場合どんな管理をしても立ちいかなくなります。
オブジェクト指向は一定数のコストを支払う代わりにファイルの分割をロジカルに行う、ポピュラーな解決方法の一つと言い換えても良いでしょう。

例題はあえて冗長に描いているように見えますが、
実戦では適切なディレクトリ構造だと思いますし、メンテされている前提ですがかなり良いプロジェクトだと思います。
読み方はこんな感じですかね?

1:doPrint()で問題(※)が起きていて、それはcreateRandomHage()で作られて、さらにそれはPrintFactoryで作られた、とさかのぼる。
2:そこでPrintFactoryのcreateRandomHage()を見に行く。
3:そこで生成されている、PrintWithDecisionを見に行く。
4:PrintWithDecisionを見ると、コンストラクタメソッドで引数定義したインスタンスのメソッド叩いてるだけなので追い返される
5:new createRandomHageの引数を確認


確かにオブジェクト指向は限界があると言われてまして、
近年、別ルートで問題解決する関数型プログラミングや関数型言語が注目されています。
(Scala、Haskell、F#、Elixirが有名ですかね)

メッセージ指向でやり取りするオブジェクト指向は時間経過と状態に強く左右されるので、
開発者の頭のメモリを食う量が半端じゃないのがデメリットですかね?

ただし、主流のオブジェクト指向でもそれなりに何とかやってこれていますので、
暫くはオブジェクト指向の天下は続きそうですね。
デザパタの勉強頑張ってください。


classはinterfaceに依存するように作られているため

これは自分勝手でフリーダムな動作が出来るクラス達の手綱を握るために制約を課すための機能です。
なのでどちらかと言えばポジティブなものです。
下記は使い分けの一例です。

  • 継承: 一つのクラスをロールモデルとして採用して子クラスは特化させる
  • 抽象クラス: 既存のクラスのメソッドをまとめたい、だから一部の同じ動きするメソッドは共通化しておく、でもインスタンスとして動作はできない
  • インターフェース: お前らのクラスは動きがバラバラ過ぎでロジックの共通化は無理!メソッドの保証だけするから、後は勝手にやってちょうだい

実質、下に行けば行くほど単純に出来る事が減ります。
一見不便でしかないのですが、継承は全ての親の存在を気にし続ける必要があるので、
用途によって適切に使い分けるとリーディングが楽になります。

これを知っていると、4の場面で太字のように軌道修正されます。


デバッガーやIDEを使用、もしくは併用してみてはどうでしょう?
無料ならNetBeans、もし業務で使ってて有料でも良いものが欲しければPHPStormが良いでしょう。
PHPDocの記述も含めてリアルタイムでクラスの関係を把握してくれますので、プロジェクトが肥大化しても責務が正しく切り分けられていれば超高速にコードリーディングが出来ます。

投稿2016/04/11 07:08

編集2016/04/11 12:52
miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

i50

2016/04/11 09:17

細やかなご回答ありがとうございます! なるほど…オブジェクト指向では管理も相当重要そうですね。 一定数のコストの対策として、IDEやデバッガなどの周辺技術があるように感じました。 >4:PrintWithDecisionを見ると、コンストラクタメソッドで引数定義したインスタンスのメソッド叩いてるだけなので追い返される こちらの「追い返される」と言うのは、 手続き型の時にはあまりなかった感覚のような気がします。 PrintWithDecisionが何かを継承していたり、抽象クラスの実装だったりした場合、 制約元の親クラスを見に行くという感じかなと理解しました。 検索してみましたが、PHPStormすごいですね。 ぼんやりとeclipseでいいかなと思っていましたが、 比較してみようと思います。 (関数型…オブジェクト指向もまだまだというのに、私が追いつける日は来るのだろうかw) ありがとうございました!
miyabi-sun

2016/04/11 11:08

> 手続き型の時にはあまりなかった感覚のような気がします。 そうですね。 高度に抽象化された世界ならではという気がします。 PHPでも今回のようにDIコンテナを使わない限り中々お目にかかれないでしょう。 そういう意味ではとても分かりづらく、学習コストの高い概念といえそうです。 > eclipse Aptanaというeclipseの兄弟を使っていましたが、インデックスが超重いのが玉に瑕でしたね。 他の無料IDEも含めて、殆どがJavaの為に存在するIDEを間借りしてる感があります。 プロジェクト内が一貫して管理できているのならばAtomやSublimeTextでも良いかもしれませんね。
i50

2016/04/12 03:27

>高度に抽象化された世界ならではという気がします。 >そういう意味ではとても分かりづらく、学習コストの高い概念といえそうです。 オブジェクト指向は抽象化とか目新しくて面白いですが、では実際に何を抽象化するかと考えると難しいなと感じています。 さすがに一つのパラダイムと言われるだけあって、かなりの学習コストの高さを感じています…。 >AtomやSublimeText こちらは軽そうです! ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問