- PR -

クラスにちょっとだけ追加属性を持たせたい場合、オブジェクト指向的にはどうするのが良い?

投稿者投稿内容
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2008-12-11 12:17
言語は特に限定しないのですが、C# や Java あたりを想定しています。
たとえば、つぎのような擬似コードを考えます。Foo というインスタンスを複数管理するために、リストで持っています。

コード:
class Hoge
{
    List<Foo> fooList;
}



ここでクラス Foo に int abc; という属性を追加で関連付けたいとします。しかし、Foo のフィールドに abc を追加するほど、Foo と abc が密接な関係でもない場合、どうするのが良いかでいつも迷います。
こういう場合、私は Dictionary(Java なら HashMap) を使い、つぎのようにしています。

コード:
class Hoge
{
    List<Foo> fooList;
    Dictionary<Foo, int> fooAbcDic;
}



ただ、これだと、個数が1つを超える属性を追加したい場合、煩雑になるので、複数個入れられるラッパークラスとして Bar を作ってしまい、下記のコード例のように、Foo を key にして、Bar を検索できるようにして、追加情報があれば Bar のフィールドに詰め込むようにしています。

コード:
class Bar
{
    int abc;
    int def;
    int ghi;
    // ほかに追加したいフィールドがあれば複数のフィールドを書く。
}

class Hoge
{
    List<Foo> fooList;
    Dictionary<Foo, Bar> fooBarDic;
}



これしかないですかね?もっとエレガントな方法ってないものでしょうか?という漠然とした質問になります。
私が思っているこれでは嫌な点としては、Dictionary を使うと、ハッシュで検索になりコストが高いような気がするし、Foo に安易に equals メソッドを定義できなくなります。あと、Bar というどうでもいいクラスを作らないといけない点も木になります。とはいえどれも別にどうということでもない些細なことなのですが。

質問を言い換えますと、インスタンスとインスタンスを緩く結びつけて管理したい場合、どうするのが良いか?ということです。あと、こういう問題になにかパターンのような名前って付いているでしょうか?
ぴあちゃん
ぬし
会議室デビュー日: 2008/02/07
投稿数: 287
投稿日時: 2008-12-11 12:26
コード:
public class FooBase {
   protected HashMap baseMap = new HashMap();
}
public class Foo extends FooBase {
   private List<Bar> barList = new List<Bar>();
   public void setAbc(int abc) {
      baseMap.put("ABC", new Integer(abc));
   }
}



とか駄目?

よこけん
大ベテラン
会議室デビュー日: 2006/01/31
投稿数: 216
投稿日時: 2008-12-11 12:39
引用:
unibonさんの書き込み (2008-12-11 12:17) より:

Foo のフィールドに abc を追加するほど、Foo と abc が密接な関係でもない場合



その "場合" によりけりかもですが、オブジェクト指向的には、Foo と abc の 2 つの属性を持つ別クラスを定義するってトコでしょうか。
もちろん、そのクラスに適切な名前を付ける (=適切な責任を持たせる) 必要があります。
例えば、書籍の貸出システムで、書籍を借りている利用者を、書籍クラスの属性にしたくないという時ならば、
書籍と借りている利用者の 2 つの属性を持つ貸出クラスを定義する、とか。


引用:
unibonさんの書き込み (2008-12-11 12:17) より:

ハッシュで検索になりコストが高いような気がするし



それは別問題ですね。オブジェクト指向的に適切かどうかという視点では、それは無視してください。

_________________
C#と諸々
テッテ
ベテラン
会議室デビュー日: 2008/03/16
投稿数: 91
投稿日時: 2008-12-11 12:53
引用:

unibonさんの書き込み (2008-12-11 12:17) より:

Foo に安易に equals メソッドを定義できなくなります。




この部分に関しては、Dictionary.Comparer プロパティを使うことで解決できると思います。

でも私も、Foo と abc をセットにしたクラスを作って、そのリストで管理するように思います。
Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2008-12-11 13:31
こんにちは。

可能であるなら、
最初から付加情報を格納できるようにクラス設計しとけばよいのではないでしょうか?

Microsoft製なんかだと、よくTagプロパティなんてものがありますよね。

indigo-x
大ベテラン
会議室デビュー日: 2008/02/21
投稿数: 207
お住まい・勤務地: 太陽の塔近く
投稿日時: 2008-12-11 13:49
引用:

unibonさんの書き込み (2008-12-11 12:17) より:
Foo のフィールドに abc を追加するほど、Foo と abc が密接な関係でもない場合、どうするのが良いかでいつも迷います。



インタフェースIFooExtenderを作成してFooとabcの密接な関係を

作ればいいのでは。。。。∋(・ω・)∈

ダメ?



unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2008-12-11 18:29
みなさまコメントありがとうございます。

引用:

ぴあちゃんさんの書き込み (2008-12-11 12:26) より:
コード:
   public void setAbc(int abc) {
      baseMap.put("ABC", new Integer(abc));
   }



とか駄目?


ありがとうございます。継承を使ったほうが良いのかどうかも含めて悩んでいます。
なお、私は件名に「ちょっとだけ追加属性を持たせたい」と書き、これが紛らわしかったかもしれませんが、今のところ動的である必要はないです。静的に解決できれば良いので、"ABC" のようなキーを使うことはしなくても良いと考えています。


引用:

よこけんさんの書き込み (2008-12-11 12:39) より:
その "場合" によりけりかもですが、オブジェクト指向的には、Foo と abc の 2 つの属性を持つ別クラスを定義するってトコでしょうか。


たとえば
コード:
class FooAbc
{
    Foo foo;
    int abc;
}


コード:
class Hoge
{
    List<FooAbc> FooAbcList;
}


のようにもできますね。
考えてみると、私の悩みは、Dictionary<Foo, Bar> でも書けるし List<FooAbc> でも 書けるし、どちらも書けばちゃんと動くのはたしかだけど、場面場面でどう使い分ければいいかが分からないという感じなのかもしれません。

引用:

よこけんさんの書き込み (2008-12-11 12:39) より:
それは別問題ですね。オブジェクト指向的に適切かどうかという視点では、それは無視してください。


これはご指摘のとおりだと思います。


引用:

テッテさんの書き込み (2008-12-11 12:53) より:
この部分に関しては、Dictionary.Comparer プロパティを使うことで解決できると思います。


これは存在を知りませんでした。new するときに指定できますね。
(Java の時には同じことができるのかが少し気になりますが、もっとも私は最近は Java は使っていないので、あまり制限にはならないです。)


引用:

Tdnr_Symさんの書き込み (2008-12-11 13:31) より:
可能であるなら、
最初から付加情報を格納できるようにクラス設計しとけばよいのではないでしょうか?

Microsoft製なんかだと、よくTagプロパティなんてものがありますよね。


今のところ、拡張が容易なような設計、ということはあまり目指していなくて、最初からカッチリと固まった設計で大丈夫です。
Foo クラスに、最初からいろいろフィールド(メンバー変数)を追加すれば、アクセスも高速だしコードも簡素になって良いのですが、Foo の中に入れないほうが良さそうな情報というものがあり、悩んでいます。
たとえば、Person クラスがあって、フィールドとして name, age, address, ... があった場合、そこに所有車の Car クラスを追加のフィールドとして入れるかどうか、という感じです。車を保有しているということは人の持つ属性ではなく、人と車のつながりにすぎないかなあ、という感じです。こういう疎なつながり関係のときにどう管理しようかで悩んでいます。
(ただこれを言い出すと、じゃあ address も、Car と同様の扱いにすべきでは、ということになりフィールドとして入れるものがほとんどなくなってしまいます。これについてもちょっと良く分かっていません。)

引用:

indigo-xさんの書き込み (2008-12-11 13:49) より:
インタフェースIFooExtenderを作成してFooとabcの密接な関係を

作ればいいのでは。。。。∋(・ω・)∈


インターフェースですか。継承に似た感じになるのでしょうか。ちょとイメージが掴めませんでした。ちょっと考えてみます。ありがとうございます。
オウオウ
常連さん
会議室デビュー日: 2008/11/26
投稿数: 38
投稿日時: 2008-12-11 18:33
(利用規約違反のため削除いたしました。@ITクラブメンバーシップセンター)

スキルアップ/キャリアアップ(JOB@IT)