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

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

ただいまの
回答率

90.48%

  • PHP

    20878questions

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

  • オブジェクト指向

    293questions

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

  • デバッグ

    99questions

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

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

解決済

回答 5

投稿

  • 評価
  • クリップ 13
  • VIEW 6,594

i50

score 203

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

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

//表示してよいか判断する機能。
interface IDecideToPrint {
    public function canPrint();
}

//表示する機能。
interface IPrint {
    public function doPrint();
}

//指定されたパーセンテージの確率で表示される。
class AtRateOfPercentage implements IDecideToPrint {
    private $_percent;
    function __construct($percent){
        $this->_percent = $percent;
    }
    public function canPrint(){
        return (rand(1, 100) <= $this->_percent);
    }
}

//hageと表示する。
class PrintHage implements IPrint {
    public function doPrint(){
        print 'hoge';
    }
}

//指定された文字を表示する。
class PrintParam implements IPrint {
    private $_str;
    function __construct($str){
        $this->_str = $str;
    }
    public function doPrint(){
        print $this->_str;
    }
}

//判断つきで表示する機能。
class PrintWithDecision implements IPrint {

    private $_decide;
    private $_print;

    function __construct(IDecideToPrint $decide, IPrint $print){
        $this->_decide = $decide;
        $this->_print = $print;
    }

    public function doPrint(){
        if($this->_decide->canPrint()){
            $this->_print->doPrint();
        }
    }
}

//様々なIPrintの実装を生成する。
class PrintFactory {
    /**
     * 常にfugaと表示する。
     * @return IPrint
     */
    public function createAlwaysFuga(){
        return new PrintParam('fuga');
    }
    /**
     * 50%の確率でhageと表示する。
     * @return IPrint
     */
    public function createRandomHage(){
        return new PrintWithDecision(
            new AtRateOfPercentage(50)
            ,new PrintHage()
        );
    }
}

$printFactory = new PrintFactory();
$alwaysFuga = $printFactory->createAlwaysFuga();
$randomHage = $printFactory->createRandomHage();

$alwaysFuga->doPrint(); //fugaと表示
$randomHage->doPrint(); //hageと表示されたりされなかったり(※)

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

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

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

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

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

よろしくお願いします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+14

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

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/11 12:52

    ご回答ありがとうございます。

    デバッガを使われたり、単体テストで責任の所在を明確化していきますと、
    オブジェクト指向で書かれたプログラムをコードリーディングで読み進めるスキルは、
    あまり使われないスキルとなりそうですね。

    そうなりますとデバッグの取っ掛かりとしては、
    ソースを追うのではなく、
    「hageと表示する機能」をドキュメント等から探すということになりそうですね。

    そう考えますと、
    オブジェクト指向はその考え方の習得だけではなく
    デバッガ、phpDoc、PHPUnitと、周辺のものも勉強する必要があるなと感じました。

    ありがとうございました!

    キャンセル

  • 2016/04/11 20:59 編集

    >オブジェクト指向で書かれたプログラムをコードリーディングで読み進めるスキルは、
    あまり使われないスキル

    どちらかというと、読まなければいけない範囲が絞られるのであって、スキルとしては必要ですね。たしかに”量”という意味では減る傾向にあると思います。

    >そうなりますとデバッグの取っ掛かりとしては、
    ソースを追うのではなく、
    「hageと表示する機能」をドキュメント等から探すということになりそうですね。

    そうですね。コードリーディングに時間をかける割合が減り、クラスの「構造」や「関連」を把握するのに時間をかける割合が増える感覚があります。
    また、IDEなどだと呼び出し階層を表示したりなど、そのメソッドやクラスの階層構造を表示する機能なども充実しているため、ドキュメントを遡る手間は大きく削減できます。

    キャンセル

  • 2016/04/12 12:37

    >たしかに”量”という意味では減る傾向にあると思います。

    量が減るのは助かります!
    確かにサンプルのソースも、問題のclassにたどり着けたならば
    見るべきは1行だけですものね。


    >また、IDEなどだと呼び出し階層を表示したりなど、そのメソッドやクラスの階層構造を表示する機能なども充実しているため、ドキュメントを遡る手間は大きく削減できます。

    IDEの特徴とか機能を十分に生かせるような書き方(コードのお作法的な?)、
    というのも重要だなと感じました。

    キャンセル

+8

こんにちは。

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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/11 12:52

    ご回答ありがとうございます。

    ソースコードを読むという静的解析が困難で、
    動的解析しかないとなりますと、
    実際に動かせるテスト環境も用意する必要があると感じました。

    多様性を使う使わないの判断基準につきましては、
    重要な事と感じましたので、調べてみたり考えてみたりしたいと思います。

    ありがとうございました!

    キャンセル

+7

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

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/11 12:53

    ご回答ありがとうございます。

    オブジェクト指向のソースは、テキストベースで追うのは難しいが、
    機能や関連性でまとまる様になるので、機能や関連性で追えば容易になる、
    ということですね。

    そうなりますと、
    いかに機能や関連性でまとまるように、様々なclassを配置整理するかというのは
    かなり重要のように感じます。

    また、IDEの使い方も習熟する必要があると感じました。
    オブジェクト指向は、周辺の技術があってこその技術なのですね。

    ありがとうございました!

    キャンセル

+5

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

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

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

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

<?php
class Printer {
    private $str;
    function __construct($str){
        $this -> str = $str;
    }
    public function print(){
        echo $this->str ;
        echo "\n";
    }
}

//Printerオブジェクトのちょっとだけ変わったオブジェクトなので継承を使う
class RamdamizePrinter extends Printer{
    private $parsent;
    function __construct($str, $percent){
        //そのまま使えるコードは再利用
        parent::__construct($str);
        $this->percent = $percent;
    }
    public function print(){
        if(rand(1, 100) <= $this->percent) {
            parent::print();
        }
    }
}

class PrinterFactory {
    // どのオブジェクトを呼び出すべきかの判断は
    // 呼び出し元は気にしなくていいようにするのがFactoryの利点
    public function create($value){
        if($value == 'hoge') {
            return new RamdamizePrinter('hoge', 50);
        } else {
            return new printer($value);
        }
    }
}

$arr = array("fuga", "hoge");
$printerFactory = new PrinterFactory();

//同じ変数に入れるなどしないと、多態の意味がない
foreach ($arr as $value) {
    $some = $printerFactory->create($value);
    $some->print();
}
?>


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

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

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/11 13:24

    ご回答ありがとうございます。

    ソースコードまで提示していただきましてありがとうございます!
    とてもスッキリしていて追いやすいです。
    interfaceではなく、classになっていると読みやすいのですね。

    適材適所を考えてソースを書くことを注意していきたいと思います。
    金づちを持つとすべてが釘に見える、という言葉が思い出されました…。

    不慣れのため、サンプルが適切ではなかったなと感じてはおります…。
    まず、なんでも抽象に依存させておこう、という意識でした。

    ありがとうございました!

    キャンセル

  • 2016/04/11 16:24

    覚えたてのやり方は取り合えず使ってみるという方法は、何かをみにつけるのに良い方法だと思います。

    私の場合は、抽象化の範囲は利用する方のコードが、「細かいこと知らんが、これやっといて」ですむように書くことだと考えています。

    キャンセル

  • 2016/04/11 18:23

    ありがとうございます!

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

    キャンセル

+3

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

オブジェクトの本質は、ロジックを責務で細分化し、ファイルやディレクトリで分けて管理することにあります。
システムが肥大化した結果、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 18:17

    細やかなご回答ありがとうございます!

    なるほど…オブジェクト指向では管理も相当重要そうですね。
    一定数のコストの対策として、IDEやデバッガなどの周辺技術があるように感じました。


    >4:PrintWithDecisionを見ると、コンストラクタメソッドで引数定義したインスタンスのメソッド叩いてるだけなので追い返される
    こちらの「追い返される」と言うのは、
    手続き型の時にはあまりなかった感覚のような気がします。

    PrintWithDecisionが何かを継承していたり、抽象クラスの実装だったりした場合、
    制約元の親クラスを見に行くという感じかなと理解しました。


    検索してみましたが、PHPStormすごいですね。
    ぼんやりとeclipseでいいかなと思っていましたが、
    比較してみようと思います。

    (関数型…オブジェクト指向もまだまだというのに、私が追いつける日は来るのだろうかw)
    ありがとうございました!

    キャンセル

  • 2016/04/11 20:08

    > 手続き型の時にはあまりなかった感覚のような気がします。
    そうですね。
    高度に抽象化された世界ならではという気がします。
    PHPでも今回のようにDIコンテナを使わない限り中々お目にかかれないでしょう。
    そういう意味ではとても分かりづらく、学習コストの高い概念といえそうです。

    > eclipse
    Aptanaというeclipseの兄弟を使っていましたが、インデックスが超重いのが玉に瑕でしたね。
    他の無料IDEも含めて、殆どがJavaの為に存在するIDEを間借りしてる感があります。
    プロジェクト内が一貫して管理できているのならばAtomやSublimeTextでも良いかもしれませんね。

    キャンセル

  • 2016/04/12 12:27

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

    >AtomやSublimeText
    こちらは軽そうです!
    ありがとうございます!

    キャンセル

関連した質問

同じタグがついた質問を見る

  • PHP

    20878questions

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

  • オブジェクト指向

    293questions

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

  • デバッグ

    99questions

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