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 ab
をRoot
のメンバー変数にすることができます。 Root
が少し小さくなり、クリーンになり、管理しやすくなりました。問題は、この構成リファクタリング後のab
のアクセスレベルについてです。
この場合、ab
がパブリックメンバーになっても大丈夫ですか?欠点はありますか?私が読んだことから、一般のメンバーは一般的に悪いデザインと見なされます。しかし、ここでは全体的なカプセル化/露出は実際には変更されていません...オブジェクトa
とb
はAB
内でプライベートなので、外部からはまだ隠されています。
(補足:ab
を公開したい理由は、Root
の構成階層を簡単にトラバースできるようにするためです。たとえばRoot
のメンバーc
func1
に電話したいと思うかもしれません:
void C::foo(Root& root) {
//do some stuff
root.ab.func1();
}
ab
がプライベートの場合、root
でパススルー関数を定義する必要があります。)
クラスCがfunc1()
を呼び出したい場合は、ab
オブジェクトを渡す代わりに、foo
オブジェクトをCのroot
関数に渡します。これは、他のプログラマーと将来のあなたに何が起こっているかをよりよく説明しています。これは、Cがその仕事をするためにすべてのルートを必要とせず、ABだけを必要とすることを示しています(そして、おそらくルート以外のソースからABを取得する可能性があります)。
_void C::foo(AB& ab) {
//do some stuff
ab.func1();
}
_
私があなたなら、ルートにアクセスしている他のクラスを調べて変更し、ABのfunc1()
(およびABクラスに移動する他の関数)を呼び出すだけです。
他の方法でもルートを分割することを視野に入れてこれを行います。あなたが言うようにそれが非常に大きい場合、それから出ようとする小さなクラスがたくさんある可能性があります...
学問的および技術的な観点から、それはnotです。
学術的な観点から、あなたはカプセル化の原則に違反しています。
技術的な観点から、将来さらにリファクタリングを行う必要がある場合は、多くの作業が必要になります。
そうは言っても、これに要約すると、実用的な観点もあります。IDEが、ab
をパブリックからプライベートにリファクタリングする機能を提供する場合、追加します。必要なすべてのアクセサーと、root.ab
へのすべての参照を、コードベース全体でこれらのアクセサーの呼び出しに置き換えます。数回クリックしてキーストロークするだけでそれが可能であれば、問題ありません。そうでない場合は、より適切です。オフにしないでください。
サブオブジェクトc
が何を意味するのかは私にはわかりませんが、サブクラスを意味する場合は、ab
protectedにすることを検討してください。このようにして、c
はそれにアクセスできますが、外部コードはアクセスできません。