web-dev-qa-db-ja.com

クラスをインターフェースとして使用する際の制限

私は現在、組み込みソフトウェア開発者としてトレーニングと作業を行っている電気エンジニアであるため、正式なコンピューターサイエンスとソフトウェア設計のトレーニングはほとんどありません。私は数ヶ月前までCと関数型プログラミングでしか働いていませんでしたが、最近C++とOOP組み込みLinuxの場合は開発ガイドラインに疑問のあるチームで働き始めました。パフォーマンスは問題ではありません。このプロジェクト。

サブモジュールのインターフェイスとしてクラスを使用する必要があります。つまり、ライブラリインターフェイスヘッダーは、クラスを使用するプロセス(現時点では他のライブラリが必要としない)によってインスタンス化されるクラスを宣言し、そのメソッドがAPIを構成します。また、グローバル変数を使用することはできません。 e。クラスは、必要になる可能性のあるすべてのデータをカプセル化する必要があります。私はそのようなことを見たことがありませんでした-私は「スタンドアロン」(より良いWordがないため)関数(init()open()get/set/reset()doSomething()、...)、ファイルスコープを持ついくつかのグローバル変数を持ち、ほとんどextern(グローバルとエクスターンの使用は状況によっては眉をひそめる可能性があることを認識しており、使用しても問題ありません)。このアプローチでこれまでに見つけた問題:

  • 条件付きアクセス:通常、ファイルスコープを使用してミューテックス変数を作成し、それをinit()関数で開始し、ゲッター/セッターやその他の必要な場所で使用しました。これで、複数のプロセスでインスタンス化される外部リソースを変更するクラスができました。このようなアーキテクチャでは、限定受信システムを実装できますか?現時点での私の解決策は、共有リソースを処理し、オブジェクトからのリクエストを順番に処理するための専用タスクを用意することです(オブジェクトはタスクへのリクエストの送信に制限されます)。

  • コードの繰り返し:クラスは気密であるため、繰り返される関数とデータがいくつかあります。たとえば、関連する(ただし異なる)入力値を変換してから、出力をデータベースに書き込む3つのクラスがあります。 db書き込み関数はクラス間で非常によく似ており、以前のアプローチでは、これらの操作を処理する単一のスタンドアロン関数を作成していました。このためのサブクラスを構築することはできますが、この場合、複雑さと読みやすさが増すことは、特にコードベースでの実践ではないことを考えると、それを正当化するものではないと思います。私がそのルートを採用する場合、この比較的単純な機能のために、1つのメソッドのみを実装する3つのサブクラスがあります-そしてそれは私の意見ではあまりにも衒学的です。

コードをレビューする前の私のアプローチは、スタンドアロン関数を備えたAPIであり、ライブラリ内部のクラスを使用して、データ間の関係をキャプチャしようとしました。 (簡略化された)例として、私は次の場所から移動する必要がありました。

/*+++++
file translation.cpp
++++++*/

class translation1{
    int CurrentTranslation;
public:
    void translate(int);
    int getTranslation();
};
class translation2{
    int CurrentTranslation;
public:
    void translate(int); //translation is different from translation1
    int getTranslation();
};
...
class translation1 Translation1;
class translation2 Translation2;
...
void init()
{
    ...
}
void translateAll(int one, int two)
{
    Translation1.translate(one);
    Translation2.translate(two);
    ...
}
saveToDatabase()
{
    one = Translation1.getTranslation();
    two = Translation2.getTranslation();
    ....
}

に:

/*+++++
file translation.h
++++++*/

class translation1{
    int CurrentTranslation;
public:
    translate(int);
    int getTranslation();
    saveToDatabase();
};
class translation2{
    int CurrentTranslation;
public:
    translate(int); //translation is different from translation1
    int getTranslation();
    saveToDatabase();
};
...

最後のアプローチは、データに関係のないメソッドでクラスを汚染していることがわかりました。

OOP自分が正しくないと感じているパラダイムへのアプローチによって形作られ、汚染されていると感じているので、それが業界で受け入れられている慣行とどのように関連しているかを理解しようとしています。 、セカンダリレベルで、業界のベストプラクティスを使用します。この開発アプローチから他にどのような制限が予想されますか?

私の苦労は、OOPへの変更、悪い開発ガイドラインに起因するのでしょうか、それともOOPパラダイム自体の制限に起因するのでしょうか?

1
calofr

あなたの例では、あなたのアプローチと「必須」アプローチについて詳しく説明していません。

私が指摘できることの1つは、あなたが直感したように、saveToDatabase()は適切に翻訳プロセスの一部ではないということです。元の翻訳クラスには、ある種の翻訳を実行するという1つの責任があります。データベースへの保存は別の責任であり、別のクラスのオーケストレーション関数で実行する必要があります。

ただし、翻訳クラスは、シリアル化されたフォームを提供することにより、saveToDatabase()機能を支援する責任があります。あなたの例では、intの結果はシリアル化された形式ですが、文字列またはバイナリエンコーディングの場合もあります。

リソースへの条件付きアクセスは引き続き実行できますが、範囲と管理は異なります。 2つのオブジェクトがインスタンス化されているとします。どちらも、初期化パラメーターのみが異なるクラスtranslationです。グローバルリソースまたは共有リソースがない場合、ミューテックスを静的にすると、共有状態がないために必要とされない2つのオブジェクト間に干渉が発生します。

一方、変換オブジェクト間に共有状態がある場合は、それを別のオブジェクトに抽出して、変換オブジェクトが状態を適切に共有するために使用できるようにする必要があります。データベースへの保存は良い例です。したがって、データベースへのアクセスを管理するオブジェクトが個々の翻訳オブジェクトからseparateであると、コードの保守性が大幅に向上します。

ボイラープレートまたは繰り返しコードがある場合は、いくつかの方法で対処できます。共通に保持されている機能のほとんどを実装する共通基本クラスを作成できます。または、翻訳クラスが委任できるコンパニオンクラスを作成することもできます。

0
BobDalgleish