web-dev-qa-db-ja.com

構成でパブリックメンバーオブジェクトを使用するための許容可能な設計?

Rootという大きなクラスがあり、多くのメンバーと関数があるとします。

class Root {
public:
    void func1(); // operates on a and b
    void func2(); 
    ...       
private:
    A a;
    B b;
    C c;
    ...
};

クラスRootは少し大きくなっているので、いくつかのメンバー変数と関数を別のクラスに分解することにします。

class AB {
public:
    void func1();
    ...
private:
    A a;
    B b;
};

次に、コンポジションを使用して、AB abRootのメンバー変数にすることができます。 Rootが少し小さくなり、クリーンになり、管理しやすくなりました。問題は、この構成リファクタリング後のabのアクセスレベルについてです。

この場合、abがパブリックメンバーになっても大丈夫ですか?欠点はありますか?私が読んだことから、一般のメンバーは一般的に悪いデザインと見なされます。しかし、ここでは全体的なカプセル化/露出は実際には変更されていません...オブジェクトabAB内でプライベートなので、外部からはまだ隠されています。

(補足:abを公開したい理由は、Rootの構成階層を簡単にトラバースできるようにするためです。たとえばRootのメンバーcfunc1に電話したいと思うかもしれません:

void C::foo(Root& root) {
    //do some stuff
    root.ab.func1();
}

abがプライベートの場合、rootでパススルー関数を定義する必要があります。)

3
badger5000

クラスCがfunc1()を呼び出したい場合は、abオブジェクトを渡す代わりに、fooオブジェクトをCのroot関数に渡します。これは、他のプログラマーと将来のあなたに何が起こっているかをよりよく説明しています。これは、Cがその仕事をするためにすべてのルートを必要とせず、ABだけを必要とすることを示しています(そして、おそらくルート以外のソースからABを取得する可能性があります)。

_void C::foo(AB& ab) {
    //do some stuff
    ab.func1();
}
_

私があなたなら、ルートにアクセスしている他のクラスを調べて変更し、ABのfunc1()(およびABクラスに移動する他の関数)を呼び出すだけです。

他の方法でもルートを分割することを視野に入れてこれを行います。あなたが言うようにそれが非常に大きい場合、それから出ようとする小さなクラスがたくさんある可能性があります...

2
Daniel T.

学問的および技術的な観点から、それはnotです。

学術的な観点から、あなたはカプセル化の原則に違反しています。

技術的な観点から、将来さらにリファクタリングを行う必要がある場合は、多くの作業が必要になります。

そうは言っても、これに要約すると、実用的な観点もあります。IDEが、abをパブリックからプライベートにリファクタリングする機能を提供する場合、追加します。必要なすべてのアクセサーと、root.abへのすべての参照を、コードベース全体でこれらのアクセサーの呼び出しに置き換えます。数回クリックしてキーストロークするだけでそれが可能であれば、問題ありません。そうでない場合は、より適切です。オフにしないでください。

サブオブジェクトcが何を意味するのかは私にはわかりませんが、サブクラスを意味する場合は、abprotectedにすることを検討してください。このようにして、cはそれにアクセスできますが、外部コードはアクセスできません。

2
Mike Nakis