私は自分のアプリケーションを設計しているだけで、SOLIDとOOP=が正しく理解されているかどうかわかりません。クラスは1つのことを行い、他のことからうまくいくはずです手は、私たちが扱う実際のオブジェクトを表す必要があります。
私の場合、データセットで特徴抽出を行ってから、機械学習分析を行います。 3つのクラスを作成できると思います
ただし、FeatureExtractorクラスは何も表現せず、クラスというよりルーチンのようなものを実行します。使用される関数は1つだけです。extract_features()
1つのことを表すのではなく1つのことを行うクラスを作成することは正しいですか?
編集:それが重要かどうかはわかりませんが、私はPythonを使用しています
そして、extract_features()がそのように見える場合、そのメソッドを保持する特別なクラスを作成する価値はありますか?
def extract_features(df):
extr = PhrasesExtractor()
extr.build_vocabulary(df["Text"].tolist())
sent = SentimentAnalyser()
sent.load()
df = add_features(df, extr.features)
df = mark_features(df, extr.extract_features)
df = drop_infrequent_features(df)
df = another_processing1(df)
df = another_processing2(df)
df = another_processing3(df)
df = set_sentiment(df, sent.get_sentiment)
return df
クラスは1つのことを行う必要があります。
はい、それは一般的に良いアプローチです。
しかし一方で、それらは私たちが扱う実際のオブジェクトを表す必要があります。
いいえ、それは私見のよくある誤解です。初心者がOOPにアクセスすることはよくあります "現実の世界からのものを表すオブジェクトで始まる")、それは本当です。
ただし、あなたはこれで止めるべきではありません!
クラスは、プログラムをさまざまな方法で構造化するために使用できます(使用する必要があります)。現実の世界からのオブジェクトのモデリングはこれの1つの側面ですが、それだけではありません。特定のタスク用のモジュールまたはコンポーネントを作成することは、クラスのもう1つの賢明なユースケースです。 「機能エクストラクタ」はおそらくそのようなモジュールであり、1つしか含まれていないpublic method extract_features()
でも、多くのプライベートメソッドが含まれておらず、多分いくつかの共有状態。したがって、クラスFeatureExtractor
があると、これらのプライベートメソッドの自然な場所が導入されます。
注意事項:Pythonのような言語では、個別のモジュールの概念をサポートしています。このためにモジュールFeatureExtractor
を使用することもできますが、コンテキストではこの質問の中で、これは私見で無視できる程度の差です。
さらに、「特徴抽出器」は「特徴を抽出する人またはボット」と考えることができる。これは抽象的な「もの」であり、現実の世界では見つけられないかもしれませんが、名前自体は有用な抽象化であり、そのクラスの責任が何であるかを誰もが理解できるようにします。そのため、このクラスは「何も表さない」ことに同意しません。
Doc Brownは注目されています。クラスは実際のオブジェクトを表す必要はありません。それらは便利である必要があります。クラスは基本的に単なる追加の型であり、int
またはstring
は実際には何に対応しますか?それらは抽象的な説明であり、具体的で具体的なものではありません。
とはいえ、あなたのケースは特別です。あなたの説明によると:
そして、extract_features()がそのように見える場合、そのメソッドを保持する特別なクラスを作成する価値はありますか?
正解です。コードが図のようになっている場合、それをクラスにしても意味がありません。 有名な話 があり、Pythonでのクラスのそのような使用はコードのにおいであり、単純な関数で十分であることが多いと主張しています。あなたのケースはこれの完璧な例です。
クラスの過剰使用は、1990年代にOOPでJavaが主流になったためです。残念ながら、当時のJavaには、いくつかの最新の言語機能(クロージャーなど)がありませんでした。そのため、多くの概念は、クラスを使用せずに表現するのが困難または不可能でした。たとえば、最近までJavaでは、状態を保持するメソッド(つまり、クロージャ)を持つことは不可能でした。代わりに、状態を保持するクラスを作成する必要があり、これにより単一のメソッド(invoke
などと呼ばれる)が公開されました。
残念ながら、このスタイルのプログラミングはJavaをはるかに超えて人気を博しました( 影響力のあるソフトウェアエンジニアリングの本 が原因で、そうでなければ非常に便利です)。そのような回避策が必要です。
Pythonでは、クラスは明らかに非常に重要なツールであり、自由に使用する必要があります。ただし、これらはonlyツールではなく、意味のないところで使用する理由はありません。無料の機能はOOPに役立たないというのはよくある誤解です。
私はアプリケーションを設計しているだけで、SOLIDとOOPを正しく理解しているかどうかはわかりません。
20年以上経ちましたが、どちらかわかりません。
クラスは1つのことを実行し、それをうまく実行する必要があります
ここで間違えにくい。
それらは、私たちが扱う実際のオブジェクトを表す必要があります。
まあ、本当に?これまでで最も人気があり成功したクラス、String
をご紹介します。テキストに使用します。そして、それが表す現実のオブジェクトはこれです:
なぜだめなのか、すべてのプログラマーが釣りに夢中になっているわけではありません。ここでは、メタファーと呼ばれるものを使用しています。実際には存在しないもののモデルを作成することは問題ありません。それは明確でなければならない考えです。あなたの読者の心の中で画像を作成しています。これらの画像は本物である必要はありません。簡単に理解できました。
良いOOP設計は、メッセージ(メソッド)をデータ(状態)の周りにクラスター化するので、それらのメッセージへの反応はそのデータに応じて変化する可能性があります。 、まあ。読者にとって理にかなっている限り、問題ありません。
これで、次のように考えることができます。
しかし、これをメタファーを利用する前に現実の世界に存在させる必要があると考える場合、プログラミングのキャリアには多くの芸術や工芸が関わっています。
注意してください! SOLIDクラスは「1つのことだけを行う」と言うわけではありません。その場合、クラスには単一のメソッドしかなく、クラスとクラスの違いは実際にはありません。機能。
SOLIDは、クラスは単一の責任を表す必要があると述べています。これらは、チームの人の責任のようなものです。ドライバー、弁護士、スリ、グラフィックデザイナーなど。これらの人はそれぞれ、複数の(関連する)タスクを実行できますが、すべてが1つの責任に関係します。
これのポイントは-要件に変更があった場合、理想的には単一のクラスを変更するだけで済みます。これにより、コードが理解しやすくなり、変更が容易になり、リスクが軽減されます。
オブジェクトが「実在のもの」を表すという規則はありません。 OOだった最初にはシミュレーションで使用するために発明されたため、これは単にカーゴカルトの伝承です。しかし、プログラムはシミュレーションではありません(最近のOO applicationsは)なので、このルールは適用されません。各クラスが明確に定義された責任を負っている限り、問題はありません。
クラスに実際に単一のメソッドしかない場合およびクラスに状態がない場合は、スタンドアロン関数にすることを検討できます。これはまったく問題なく、KISSおよびYAGNIの原則に従います-関数で解決できる場合はクラスを作成する必要はありません。一方、必要と思われる理由がある場合内部状態または複数の実装の場合は、クラスを前もって作成することもできます。ここでは、最善の判断を行う必要があります。
1つのことを表すのではなく1つのことを行うクラスを作成することは正しいですか?
一般的には問題ありません。
FeatureExtractor
クラスが正確に何をすることになっているのか、もう少し具体的な説明がないと、それを伝えるのは困難です。
とにかく、FeatureExtractor
が公開extract_features()
関数のみを公開している場合でも、 Strategy
クラスで構成することを考えることができます。正確に抽出を行う必要があります。
別の例は テンプレート関数 を含むクラスです。
さらに、クラスモデルに基づく Behavioral Design Patterns があります。
明確にするためにいくつかのコードを追加したとき。
そして、extract_features()がそのように見える場合、そのメソッドを保持する特別なクラスを作成する価値はありますか?
この線
sent = SentimentAnalyser()
Strategyを使用してクラスを構成できるという意味で正確に構成されています。
そのSentimentAnalyser
クラスのインターフェースがある場合、関数の特定の実装に直接結合する代わりに、その構築時にFeatureExtractor
クラスに渡すことができます。
パターンとすべての派手な言語/概念はさておき、あなたが偶然見つけたのはJobまたはBatch Processです。
結局のところ、純粋なOOPプログラムでも、実際に作業を実行するには何かで駆動する必要があります。何らかの形でエントリポイントが存在する必要があります。たとえば、MVCパターンでは、 「C」コントローラは、GUIからクリックなどのイベントを受け取り、他のコンポーネントを調整します。従来のコマンドラインツールでは、「メイン」機能が同じことを行います。
1つのことを表すのではなく1つのことを行うクラスを作成することは正しいですか?
クラスはdoes何かであり、他のすべてのものをオーケストレーションするエンティティを表します。 Controller、Job、Mainなどの名前を付けることができます。
そして、extract_features()がそのように見える場合、そのメソッドを保持する特別なクラスを作成する価値はありますか?
それは状況に依存します(そして、これがPythonで行われる通常の方法に精通していません)。これが小さなワンショットコマンドラインツールである場合は、クラスではなくメソッドで問題ありません。あなたのプログラムの最初のバージョンは、確かにメソッドで逃れることができます。後で、そのようなメソッドが何十となることに気付いた場合は、グローバル変数が混合されていても、クラスにリファクタリングするときがきました。
OOP as modelling system of the behavior of the system。注:システムはdoes n't)ただし、現実世界のメタファーが役立つ場合があります(「パイプライン」、「ファクトリー」など)。
目的のシステムが複雑すぎて一度にすべてをモデル化できない場合は、それをより小さな部分に分解し、それらをモデル化して(「問題領域」)、さらに分解して、動作が一致する部分に到達するまで続けることができます。 (多かれ少なかれ)数値、文字列、リストなどのいくつかの組み込み言語オブジェクトのもの.
これらの単純な部分を用意したら、それらを組み合わせて、より大きな部分の動作を記述したり、さらに大きな部分に組み合わせたりすることができます。これにより、全体に必要なドメインのすべてのコンポーネントを記述できます。システム。
いくつかのクラスを作成するのは、この「結合」フェーズです。希望どおりに動作する既存のオブジェクトがない場合は、クラスを作成します。たとえば、ドメインに「foos」、「bars」と呼ばれるfoosのコレクション、「bazs」と呼ばれるバーのコレクションが含まれている場合があります。 fooは文字列でモデル化するのに十分単純であることに気づくかもしれません。 Pythonが提供するいくつかの特定の制約に従うためには、バーのコンテンツが必要であることがわかります。この場合、この制約を適用するために新しいクラスを作成する可能性があります。おそらくbazにはそのような特性はありませんなので、リストでそれらを表すことができます。
couldこれらのコンポーネント(foos、bars、bazs)のそれぞれに対して新しいクラスを作成しますが、needは既に正しいものがある場合動作。特に、クラスが有用であるためには、何か(データ、メソッド、定数、サブクラスなど)を「提供する」必要があるため、カスタムクラスのレイヤーが多数ある場合でも、最終的にmustを使用します。いくつかの組み込み機能。たとえば、foosの新しいクラスを作成した場合、おそらく文字列のみが含まれるので、fooクラスを忘れず、代わりにbarクラスにそれらの文字列を含めてみませんか?クラスも組み込みオブジェクトであることを覚えておいてください。クラスは特に柔軟なオブジェクトです。
ドメインモデルを取得したら、それらの特定のinstancesを取得して、モデル化する特定のシステムの「シミュレーション」(たとえば、「。 。」)。
このシミュレーションが完了したら、それを実行して、すぐに、...(または私たちがモデル化していたもの)の機械学習システム(のシミュレーション)が動作します。
ここで、特定の状況で、「機能抽出」コンポーネントの動作をモデル化しようとしています。問題は、「特徴抽出器」のように動作する組み込みオブジェクトがあるか、またはそれをより簡単なものに分割する必要があるかどうかです。特徴抽出器は関数オブジェクトと非常によく似ているように見えるので、モデルとして使用しても問題ないと思います。
この種の概念について学習する際に留意すべきことの1つは、言語によって、組み込みの機能やオブジェクトが異なる可能性があることです(もちろん、「オブジェクト」のような用語を使用しないものもあります!)。したがって、ある言語で意味のあるソリューションは、別の言語ではあまり役に立たない可能性があります(これは、同じ言語の異なるバージョンにも適用できます!)。
歴史的に、OOP文献(特に「設計パターン」)のlotは、Pythonとはかなり異なるJavaに焦点を当ててきました。たとえば、Javaクラスはオブジェクトではありません、Javaはごく最近まで関数オブジェクトを持っていませんでした、Javaは厳密な型チェックを備えています(これにより、インターフェースとサブクラス化)Pythonはアヒルの入力を推奨しますが、Javaにはモジュールオブジェクトがありません、Java integers/floats/etc 。はオブジェクトではなく、Javaでのメタプログラミング/イントロスペクションには「リフレクション」が必要などです。
私はJavaを選択するつもりはありません(別の例として、OOP理論は、Pythonとは非常に異なるSmalltalkを中心に展開しています)、私が指摘しようとしているのは、ソリューションが開発されたコンテキストと制約、およびそれが現在の状況と一致するかどうかについて非常に慎重に検討する必要があることです。
あなたの場合、関数オブジェクトは良い選択のようです。 「ベストプラクティス」のガイドラインで関数オブジェクトが可能な解決策として言及されていないのはなぜかと疑問に思っているのであれば、それらのガイドラインは古いバージョンのJava用に作成されたからかもしれません。
実用的に言えば、「何か重要なことを行い、分離する必要のある雑多なこと」があり、明確な家がない場合は、それをUtilities
セクションに入れて、命名規則として使用します。すなわち。 FeatureExtractionUtility
。
クラス内のメソッドの数を忘れてください。今日の単一のメソッドは、明日5つのメソッドに成長する必要があるかもしれません。重要なのは、関数のその他のコレクションのユーティリティエリアなど、明確で一貫した組織構造です。