web-dev-qa-db-ja.com

コンストラクターには何を含める必要がありますか?

コンストラクターには何を含める必要がありますか?

どちらの場合も、クラスが機能するには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);
  }
}

またはその他?

例はありますが、これらのクラスにはメソッドはありません。

2
jarer

最良のオプションは1またはのようですが、firstArgとsecondArgの詳細を確認する必要があります。たくさんの質問があります:

  1. Languageクラスの目的は何ですか?オブジェクトですか?ヘルパークラスですか?ある種のServiceクラスとリポジトリを注入できますか?
  2. 1番目と2番目の引数は誰ですか?それらはLanguageのフィールドですか?これらはLanguage?内の別のメソッドによって使用されますリポジトリは1つの方法でのみ使用されますか?

あなたが私たちに見せるものを探すだけで、最良のオプションは4です。 4つのオプションとは何ですか?

見て:

class Language {
  public void doThat(LanguageRepository repository, String firstArg, String secondArg) {  
      // code
  }
}

どうして?

  • あなたの言語クラスはヘルパークラスのようです。 firstArgsとsecondArgsがLanguageのフィールドであるかどうかは言及しません。それらがLanguage内のランダムなメソッドの処理のためにのみ渡される場合、それらを受け入れるための排他的なメソッドを持っている方が良いようです。
  • 引数は言語のフィールドではありませんLanguageクラス内の別のメソッドで使用される場合、コンストラクターにリポジトリーまたは引数を渡すことは有効です。リポジトリを使用するメソッドが1つだけの場合は、コンストラクターを配置する必要はありません。
  • クラスとメソッドの依存関係はより明確ですrepositoryと引数を必要とするメソッドは1つだけなので、.
  • 単体テストが簡単必要なメソッドは1つ(doThat)だけなので、コンストラクターでrepositoryと引数を1つのメソッドのみに使用すると、クラスの実際の依存関係が非表示になります。
3
Dherik

あなたが尋ねたところによると、あなたのクラスはdoThat()を呼び出す手段にすぎないようです。また、doThat()には、languageRepositoryfirstArg、およびsecondArgの3つの「パラメーター」が必要です。

私にとって「オブジェクト指向」とは、アプリケーションにあるすべてのインスタンスが何らかのもの(クラス名と一致する)を表す必要があることを意味しますが、あなたの質問にはそれがありません。

これからは、当て推量をする必要があります。

アプリケーションの存続期間中に、個別のfirstArgsecondArgの値を使用して、定数languageRepositoryを指定してdoThat()を複数回呼び出したいと思います。 (またはいくつかの列挙されたもの)。

アプローチ3

次に、アプローチ3(コンストラクターで3つのパラメーターをすべて設定)は、すべてのdoThat()呼び出しごとに使い捨てインスタンスを作成します。 Languageというクラス名でこれを行うと、驚きが生まれます(doThat()の呼び出しごとに新しい言語を作成する必要があるのはなぜですか?世界の言語の数は既知であり、制限されており、列挙可能です)。

一般的な使用法は次のようになります。

Language lang = new Language(repository, firstArg, secondArg);
lang.doThat();

そして、その後、langインスタンスはガベージになります-インスタンスは何の目的も果たすことはなく、静的メソッドで置き換えることができます(めったに良い選択ではありません)。

アプローチ2

アプローチ2では、事態はさらに悪化します。

LanguageDoThat lang = new LanguageDoThat(repository, firstArg, secondArg);

これは、インスタンスの作成が終了した瞬間に無駄なゴミになります。そして、ユーザーはここで、使い捨てインスタンスを作成すると実際の作業ができることを学ぶ必要があります-非常に素晴らしい驚き。

アプローチ1

これは、意味のある唯一のものです。最初に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);

代替案

LanguageRepository

メソッド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
Ralf Kleberhoff

3つの重要なアイデアがあるため、私は2に反対しています。

  1. 使用と構築を分けるのは良いことです
  2. 実際の作業を行うコンストラクターはコードの匂いです
  3. 最小驚きの原則

1)構成と使用を混在させると、コードに柔軟性がなくなり、知識を同じ時点に結び付けることができます。

2)コンストラクターが実際の作業を行う場合、共同作業者を学習し、常に同時に発生するように行動を示すという行為を強制しました。

3)これは:

new Language(languageRepository, firstArg, secondArg);

ガベージコレクタに向かう時間の無駄のように見えます。検証以外に何もすべきだったようには見えません。

BinaryMethod.invoke(languageRepository, firstArg, secondArg);

それは何かをするようです。なぞなぞを作成せずにコーディングは十分に困難です。

1
candied_orange

一般に、「構築は有効な機能オブジェクトを生成する」アプローチをとるので、3つすべてを使用するコンストラクターを作成します。

ただし、デフォルトのコンストラクターが機能する必要のあるオブジェクトファクトリーで、凝った操作を行う必要がある場合があります。これはあなたの言語に依存します。

いずれの場合も、notを実行するコンストラクターを操作状態で生成する必要がある場合は、各メソッドをチェックインし、InvalidOperationExceptionまたは問題の詳細と同様の何かをスローして、必要なことを確認する必要がありますプロパティは、メソッドが呼び出される前に設定されます。

0
Martin Maat

1 or 3アプローチ。慣例では、コンストラクターは、すぐに機能し始めるオブジェクトではなく、機能する準備ができている空のオブジェクトを作成します。

どちらも機能しますが、その後はdoThat関数をどのように使用するかによって異なります。

0
Lyes CHIOUKH