コンストラクターには何を含める必要がありますか?
どちらの場合も、クラスが機能するには3つの引数すべてが必要です。
どちらのアプローチがより良いのか、そしてその理由は?
1)
class Language {
LanguageRepository languageRepository;
Language(LanguageRepository languageRepository) {
this.languageRepository = languageRepository;
}
public void doThat(String firstArg, String secondArg) {
languageRepository(firstArg, secondArg);
}
}
2)
class LanguageDoThat {
Language(LanguageRepository languageRepository, String firstArg, String secondArg) {
languageRepository(firstArg, secondArg)
}
}
3)
class Language {
LanguageRepository languageRepository;
String firstArg;
String secondArg;
Language(LanguageRepository languageRepository, String firstArg, String secondArg) {
this.languageRepository = languageRepository;
this.firstArg = firstArg;
this.secondArg = secondArg;
}
public void doThat() {
languageRepository(firstArg, secondArg);
}
}
またはその他?
例はありますが、これらのクラスにはメソッドはありません。
最良のオプションは1またはのようですが、firstArgとsecondArgの詳細を確認する必要があります。たくさんの質問があります:
Language
クラスの目的は何ですか?オブジェクトですか?ヘルパークラスですか?ある種のServiceクラスとリポジトリを注入できますか?Language
のフィールドですか?これらはLanguage
?内の別のメソッドによって使用されますリポジトリは1つの方法でのみ使用されますか?あなたが私たちに見せるものを探すだけで、最良のオプションは4です。 4つのオプションとは何ですか?
見て:
class Language {
public void doThat(LanguageRepository repository, String firstArg, String secondArg) {
// code
}
}
どうして?
Language
のフィールドであるかどうかは言及しません。それらがLanguage
内のランダムなメソッドの処理のためにのみ渡される場合、それらを受け入れるための排他的なメソッドを持っている方が良いようです。Language
クラス内の別のメソッドで使用される場合、コンストラクターにリポジトリーまたは引数を渡すことは有効です。リポジトリを使用するメソッドが1つだけの場合は、コンストラクターを配置する必要はありません。repository
と引数を必要とするメソッドは1つだけなので、.doThat
)だけなので、コンストラクターでrepository
と引数を1つのメソッドのみに使用すると、クラスの実際の依存関係が非表示になります。あなたが尋ねたところによると、あなたのクラスはdoThat()
を呼び出す手段にすぎないようです。また、doThat()
には、languageRepository
、firstArg
、およびsecondArg
の3つの「パラメーター」が必要です。
私にとって「オブジェクト指向」とは、アプリケーションにあるすべてのインスタンスが何らかのもの(クラス名と一致する)を表す必要があることを意味しますが、あなたの質問にはそれがありません。
これからは、当て推量をする必要があります。
アプリケーションの存続期間中に、個別のfirstArg
とsecondArg
の値を使用して、定数languageRepository
を指定してdoThat()
を複数回呼び出したいと思います。 (またはいくつかの列挙されたもの)。
次に、アプローチ3(コンストラクターで3つのパラメーターをすべて設定)は、すべてのdoThat()
呼び出しごとに使い捨てインスタンスを作成します。 Language
というクラス名でこれを行うと、驚きが生まれます(doThat()
の呼び出しごとに新しい言語を作成する必要があるのはなぜですか?世界の言語の数は既知であり、制限されており、列挙可能です)。
一般的な使用法は次のようになります。
Language lang = new Language(repository, firstArg, secondArg);
lang.doThat();
そして、その後、lang
インスタンスはガベージになります-インスタンスは何の目的も果たすことはなく、静的メソッドで置き換えることができます(めったに良い選択ではありません)。
アプローチ2では、事態はさらに悪化します。
LanguageDoThat lang = new LanguageDoThat(repository, firstArg, secondArg);
これは、インスタンスの作成が終了した瞬間に無駄なゴミになります。そして、ユーザーはここで、使い捨てインスタンスを作成すると実際の作業ができることを学ぶ必要があります-非常に素晴らしい驚き。
これは、意味のある唯一のものです。最初にLanguage
を与えられた(そして定数と思われる)languageRepository
(またはいくつかの異なる言語固有のものでいくつか)を作成し、後でdoThat()
を複数回呼び出しますfirstArg
およびsecondArg
引数を変化させます。次に、Language
インスタンスは、アプリケーションに関連する言語の一部の側面を表し(doThat()
メソッドに現れます)、複数のdoThat()
呼び出しで存続します。使用法は次のようになります。
Language lang = Language.getInstance("en"); // or whatever way you choose,
// maybe Songleton Pattern,
// maybe Dependency Injection...
lang.doThat(firstArg, secondArg);
メソッドdoThat()
を言語リポジトリクラスに追加します。免責事項:意味的にそこに当てはまるかどうかを判断する必要があります。
doThat()
をLanguageクラスの静的メソッドにして、それが単純な手続き型呼び出しであることを明確にします。
public static void doThat(LanguageRepository repo, String arg1, String arg2) {
...
}
doThat()
のRunnableインターフェースを実装します。
public class LanguageDoThatRunnable implements Runnable {
private LanguageRepository repo;
private String arg1;
private String arg2;
public Language(LanguageRepository repo, String arg1, String arg2) {
this.repo = repo;
this.arg1 = arg1;
this.arg2 = arg2;
}
public void run() {
...
}
}
Runnableを使用すると、開発者は、コンストラクターで既に実行に必要なすべてのパラメーターを使用してインスタンスを作成し、引数なしのrun()メソッドで作業を行うことができます。技術的には、私たちはあなたのアプローチ3に近づいていますが、それにRunnableという名前を付けて(そしてそのインターフェースを実装して)驚くことを避けます。しかし、それはやり過ぎかもしれません。
クラスのインスタンスが何を表すことを意味するかを決定し、その後に構造が続きます。
コンストラクターは、インスタンスを概念の有効な表現にする必要があり、何でも「実行する」ことがメソッドの義務です。
3つの重要なアイデアがあるため、私は2に反対しています。
1)構成と使用を混在させると、コードに柔軟性がなくなり、知識を同じ時点に結び付けることができます。
2)コンストラクターが実際の作業を行う場合、共同作業者を学習し、常に同時に発生するように行動を示すという行為を強制しました。
3)これは:
new Language(languageRepository, firstArg, secondArg);
ガベージコレクタに向かう時間の無駄のように見えます。検証以外に何もすべきだったようには見えません。
BinaryMethod.invoke(languageRepository, firstArg, secondArg);
それは何かをするようです。なぞなぞを作成せずにコーディングは十分に困難です。
一般に、「構築は有効な機能オブジェクトを生成する」アプローチをとるので、3つすべてを使用するコンストラクターを作成します。
ただし、デフォルトのコンストラクターが機能する必要のあるオブジェクトファクトリーで、凝った操作を行う必要がある場合があります。これはあなたの言語に依存します。
いずれの場合も、notを実行するコンストラクターを操作状態で生成する必要がある場合は、各メソッドをチェックインし、InvalidOperationExceptionまたは問題の詳細と同様の何かをスローして、必要なことを確認する必要がありますプロパティは、メソッドが呼び出される前に設定されます。
1 or 3アプローチ。慣例では、コンストラクターは、すぐに機能し始めるオブジェクトではなく、機能する準備ができている空のオブジェクトを作成します。
どちらも機能しますが、その後はdoThat
関数をどのように使用するかによって異なります。