まず第一に、プログラミングをさらに一歩進めて、それをよりよくする方法について疑問に思っている(そして良い質問をする)おめでとうございます。それは素晴らしい態度であり、プログラムをさらに一歩進めることが絶対に必要です。賞賛!
ここで扱っているのは、プログラムのアーキテクチャー(または、誰に尋ねるかによっては設計)に関連する問題です。それはそれが何をするかではなく、どのようにそれを行うか(つまり、機能ではなくプログラムの構造)についてです。それはこれについて明確にすることが非常に重要です:あなたは可能性があり、完全にこれらのクラスを取る作るFile
入力などのオブジェクトを、そしてあなたのプログラムはまだ仕事ができます。さらに一歩進んですべての例外処理コードを追加し、ファイルとI / O(これはどこかで行われる)これらのクラス(...は存在しない)で、I / Oとドメインロジック(ドメインロジックは、解決しようとしている実際の問題に関連するロジックを意味する)の寄せ集めになり、プログラムは "作業"。これを単純な1回限りのものにすることを計画している場合の目標は、それが適切に機能することです。つまり、他の人に影響を与えることなくその一部を変更し、表面に出たときにバグを修正し、うまくいけばあまり多くせずに拡張することができます。追加したい新機能やユースケースが見つかった場合、その困難さ。
さて、今、答え。まず、はいTurbine
。クラスのメソッドパラメータとしてファイルを使用すると、SRPに違反します。あなたTurbine
とAirfoil
クラスファイルについては何も知らないはず。そして、はい、それを行うにはより良い方法があります。最初にそれを行う方法の1つを説明した後、それが後で改善される理由について詳しく説明します。これは単なる例であり(実際にはコンパイル可能なコードではなく、一種の疑似コード)、それを行うための1つの可能な方法です。
// TurbineData struct (to hold the data for turbines)
struct TurbineData
{
int number_of_blades;
double hub_height;
}
// TurbineRepository (abstract) class
class TurbineRepository
{
// Defines an interface for Turbine repositories, which return Vectors of TurbineData structures.
public:
virtual std::Vector<TurbineData> getAll();
}
// TurbineFileRepository class
class TurbineFileRepository: public TurbineRepository
{
// Implements the TurbineRepository "interface".
public:
TurbineRepository(File inFile);
std::Vector<TurbineData> getAll();
private:
File file;
}
TurbineFileRepository::TurbineFileRepository(File inFile)
{
// Process the File and handle everything you need to read from it
// At some point, do something like:
// file = inFile
}
std::Vector<TurbineData> TurbineFileRepository::getAll()
{
// Get the data from the file here and return it as a Vector
}
// TurbineFactory class
class TurbineFactory
{
public:
TurbineFactory(TurbineRepository *repo);
std::Vector<Turbine> createTurbines();
private:
TurbineRepository *repository;
}
TurbineFactory::TurbineFactory(TurbineRepository *repo)
{
// Create the factory here and eventually do something like:
// repository = repo;
}
TurbineFactory::createTurbines()
{
// Create a new Turbine for each of the structs yielded by the repository
// Do something like...
std::Vector<Turbine> results;
for (auto const &data : repo->getAll())
{
results.push_back(Turbine(data.number_of_blades, data.hub_height));
}
return results;
}
// And finally, you would use it like:
int main()
{
TurbineFileRepository repo = TurbineFileRepository(/* your file here */);
TurbineFactory factory = TurbineFactory(&repo);
std::Vector<Turbines> my_turbines = factory.createTurbines();
// Do stuff with your newly created Turbines
}
OK、ですから、ここでの主なアイデアは、プログラムのさまざまな部分を互いに分離または隠すことです。特に、ドメインロジックがあるプログラムのコア部分(Turbine
実際に問題をモデル化して解決するクラス)を、ストレージなどの他の詳細から分離したいと思います。まず、外界からのs TurbineData
のデータを保持する構造を定義しますTurbine
。次に、TurbineRepository
抽象クラス(インスタンス化できないクラスで、継承の親としてのみ使用されるクラス)を仮想メソッドで宣言します。基本的には、「TurbineData
外部から構造を提供する」動作を記述します。この抽象クラスは、インターフェース(動作の説明)とも呼ばれます。TurbineFileRepository
この方法は、(したがって、その動作を提供する)ことクラスが実装するためのFile
s。最後に、TurbineFactory
はa TurbineRepository
を使用してこれらのTurbineData
構造を取得し、Turbine
s を作成します。
TurbineFactory -> TurbineRepo -> Turbine // with TurbineData as a means of passing data.
なぜ私はこのようにそれをしているのですか?プログラムの内部動作からファイルI / Oを分離する必要があるのはなぜですか?プログラムの設計またはアーキテクチャの2つの主な目標は、複雑さを軽減し、変更を分離することです。複雑さを軽減するということは、個々の部分について適切かつ個別に推論できるように、物事を可能な限り単純にする(ただし単純ではない)ことを意味します。sについて考えるときTurbine
は、タービンデータが書き込まれるか、またはFile
あなたが読んでいるものがあるかどうか。Turbine
s、期間について考える必要があります。
変更を分離するとは、変更がコード内の最小限の場所に影響を与えるため、バグが発生する可能性(およびコードを変更した後に発生する可能性のある領域)が最小限に抑えられることを意味します。また、頻繁に変更されるもの、または将来変更される可能性のあるものは、変更されないものから分離する必要があります。たとえば、Turbine
データがファイルに格納される形式が変更された場合、Turbine
クラスが変更される理由はなく、のようなクラスのみTurbineFileRepository
です。Turbine
変更する必要がある唯一の理由は、より洗練されたモデリングを追加したか、基礎となる物理学が変更されたか(ファイル形式の変更よりもかなり可能性が低い)、または類似したものである場合です。
データが格納される場所と方法の詳細は、などのクラスで個別に処理する必要があります。TurbineFileRepository
その結果、はどのように機能するのか、さらにはデータが提供するデータが必要な理由すらわかりません。これらのクラスは完全にI / O例外処理を実装する必要があります。また、プログラムが外界と対話するときに発生するあらゆる種類の退屈で非常に重要なものを実装する必要がありますが、それを超えてはなりません。の機能は、これらすべての詳細から隠し、データのベクトルのみを提供することです。それは実装するものでもあるので、それを使用したい人には誰もそれを知る必要はありません。Turbine
TurbineRepository
TurbineFactory
TurbineFileRepository
TurbineData
構造。考えられる素晴らしい機能変更として、タービンと翼のデータをMySQLデータベースに保存したいとします。それが機能するために必要なことは、を実装しTurbineDatabaseRepository
てプラグインすることだけです。かっこいい?
あなたのプログラミングで頑張ってください!