これ何て呼びますか Part2

以下のような相互参照は、
感覚的には、なるべくならしない方が良いと感じるのですが、
どのようなメリット・デメリットがあるでしょうか?

class A
B* m_b

class B
A* m_a

■少なくとも、多くのクラスによって構成された巨大なDLLが、
 相互参照ばかりで作られると、
 (1)クラスAのポインタ型のメンバーが、クラスB内で値が変わりうる、
  また、クラスBを、クラスCで参照していたら、そこでも値が変わりうる。
  さらにクラスCを、クラスDで参照していたら、(略)となり、
  処理・メンバー値の変更の影響の把握が困難になる。
 (2)lib/objの作成順のミスや管理、
 (3)いずれかのクラスのリコンパイルが発生した時、
  リリース物のリコンパイルが発生しまくる。
 ということがあり、良くないと考えています。

- - - - - - - - - - - - - - -

相互にインタフェースし合う項目を、メンバーとして宣言しつつ、
そのGetter、Setterを用意すれば、強結合にせずに作れるという認識ですが合っていますか?

class A
B* m_b

int x1、y1、z1
  x1、y1、z1のGetter、Setter

class B

Privateなメンバーx、y、z

int x2、y2、z2
  x2、y2、z2のGetter、Setter
.

A 回答 (2件)

必然性が無い場合でも相互参照にしたほうが便利になる、ということがよくあります。



たとえば先ほどの大学と学生の話で、
大学の所属学生一覧は必要なのでとりあえず次のように大学を作ったとします。

class College
{
public:
 vector<Student*> students;
};

それで、各学生の所属大学内での何かの順位を取得する機能が必要だったとして、たとえば

A:student->GetRankInCollege();

のような設計にするにはstudentの所属大学の情報を得るために Student内にCollegeクラスへの参照が必要です。

ですが、相互参照が嫌という判断で、これを

B:college->GetRank(student);

のように実装したり、

C:GetRankOfStudent(college, student);

のように実装したりすることもできます。

ですが、B,Cの場合、これらの機能を利用するプログラマからすれば、
たとえば、「現在のユーザのランクをログインページに表示する」
といったことをしたい場合にいちいち

・現在ログインしている学生
・その学生が所属している大学

の2つを管理しなければならないという手間が発生します。

上記例の場合、単純にあらゆる箇所でcollege, studentのペアをちゃんと管理する、という労力が
あまり大きくないと判断すれば無駄に相互参照にする必要はありません。

ですが、そのあたりの管理を単純にしたいと思った場合に、「相互参照になるからこのような設計にはしない」
のように考えるほどのリスクは無いと思います。
    • good
    • 0
この回答へのお礼

確かに。

わかりやすい説明、ありがとうございます!

納得しました!

お礼日時:2014/02/08 04:02

人によって意見が分かれるところかもしれませんが、


相互参照自体は若干注意が必要ではあるが特に問題がある設計ではないと思います。

たとえば、

・フォルダは自分が持っているファイル、フォルダを知っている
・ファイルは自分が保存されているフォルダを知っている

とか

・学校は所属する学生を知っている
・学生は通学している学校を知っている

という感じで現実に相互参照があリますので、それをコードにしたときに相互参照する
のは自然だと思います。

質問に書かれている問題点というのは、要するに相互参照ではなく、結合度の問題です。

各モジュールの結合度が高いとまさに質問に書かれているような問題が発生するので良くありませんが、
それは相互参照でなくとも発生する一般的な問題です。

ちゃんと設計をして、低結合、工凝集なモデルを作る、というのが教科書的ではありますが一般的対策です。


これらの問題にgetter,setterは関係ありません。

オブジェクト指向言語であれば、抽象クラスやインタフェースを使って
依存度を下げるというのが定石です。


たとえば、

// 乗り物(公共交通機関的なもので)
class Vehicle
{
// 今乗っている乗客
vector<Passenger*> passengers;

// 運賃
virtual int price();
};

// 乗客
class Passenger
{
// 今乗っている乗り物
Vehicle* vehicle;
};

となっていると相互参照ですが、これをベースに

class Bus : public Vehicle
class Taxi : public Vehicle

という風に実装すると、乗客から見ると乗り物の詳細を知らなくても一般的な
交通機関のインタフェースを知っていれば、あらゆる乗り物に大体同じ方法で乗れる
というような実装ができます。

この回答への補足

なるほどです。
結合度・凝集度が大事ですね。

確かに
学生が学校を知っていて、
学校も学生を知っている例のときのなど、
(学生側からは、「授業に出る」のメソッドで、「知識」のメンバー変数が更新され、
学校側こらは、「教える」ことで、「資金」のメンバーが更新される
といったことは自然に感じます)

ただ、そういうとき、それぞれのメンバー変数に、
お互いのポインタを持ち合う必要があるかというと、
それぞれのクラスが、メソッドを「static」かつ「public」として提供すれば良いと思うのです。

補足日時:2014/01/29 00:27
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報