web-dev-qa-db-ja.com

列挙型と単一責任の原則(SRP)

私は最近列挙型で 実験 してきましたが、Java彼らは はるかに の固定セットを表すよりも多くのことができることがわかりました定数。

現在、さまざまなログ重大度レベル(情報、警告、エラーなど)を保持するために、Loggerクラスの新しい列挙型を作成することを考えていますが、なぜそれを一歩進めて列挙型を作成するべきではないのか疑問に思っています実際のロギング自体を実行し、Loggingクラスを完全に回避しますか? (私が使用しているフレームワークのおかげで、ロギングを実行するコードは非常に単純です)。

  1. 一方、一般的に言えば、これはSRPの違反ではありませんか?一般に、列挙型は、(2つの例のように)いくつかの追加機能を提供するのではなく、その主な目的(値を列挙する)を提供すべきではありませんか?
  2. 名前が示すとおりの列挙型に固執し、Javaがこのデータ型にもたらす機能を使用する誘惑を回避する必要がありますか?どのくらいの機能を搭載するかを評価するための基準は何ですか?列挙型?
3
carlossierra

おそらくそれは私が以前の人生でC/C++を使っていたからかもしれませんが、列挙型を単純に保つことを強く主張します。それらの言語では、列挙型は栄光の整数のみでした。 Javaでは、あなたが言うように、それらは本当に真のオブジェクトです。しかし、列挙型の精神は、そこに大量のコードを含めることではないと感じています-列挙型は コレクション内のすべてのアイテムの完全な順序付きリスト です。私はこの定義が好きです。なぜなら、それは動作を意味するのではなく、単なるコンテナだからです。

6
stdunbar

Javaでは、列挙型は単なる定数以上のものとして設計されています。列挙値オブジェクト(標準クラスからインスタンス化できるようなもの)ですが、いくつかの制限があります:

  • 列挙型のインスタンスは自分で制限されます。_enum Number {ONE, TWO, THREE;}_と書くと、これらの3つのインスタンスだけが生きることができると明示的に言います。
  • Javaは、列挙型のインスタンスをインスタンス化するように注意します(したがって、コンストラクターはprivateである必要があります)
  • Javaは、列挙型のこれらのインスタンスの使用を支援する一連のヘルパーメソッドも生成します(values()valueOf()、...)

それらはオブジェクトであり、オブジェクトには動作があるため、列挙型にメソッドを含めることはまったく問題ありません。

しかし、そのようなことを実行してしまうことはめったにありませんでした。私がこれを行うのは、要件またはドメインからaしか持てないことを知っているclassがあるときだけです。既知のインスタンスのセット。例:

Norm Aエネルギーをカウントするデバイスを特定する方法を説明します。

Company Xはエネルギードメインで動作しており、norm Aに従って個別に識別される3つのデバイスを生成します。これらの3つのデバイスが次のように識別されているとしましょう。

  • Device1は第1世代のもので、タイプ1です。
  • Device2は第2世代のもので、タイプ2です。
  • Device3は第2世代のもので、タイプ1です。

Company Xは、これら3つのデバイスから抽出されたデータを管理するソフトウェアを作成することを義務付けられています。

したがって、これはCompany X:からデバイスをモデル化する潜在的なクラスである可能性があります。

_public final class CompanyXDevice {
    private final int generation;
    private final int deviceType;

    public CompanyXDevice(int generation, int deviceType) {
        this.generation = generation;
        this.deviceType = deviceType;
    }

    public int[] generateHistoricalData() {
        ...
    }

    ...
}
_

ここではすべてが完全に機能する可能性があります...次のようなことができることを除いて:new CompanyXDevice(3, 3);CompanyXにはそのようなデバイスがないため、許可されるべきではありません。次のステップは、インスタンス化の可能性を制限する方法を見つけることです。これは(だけでなく)列挙型にリファクタリングすることで実現できます。

_public enum CompanyXDevice {
    DEVICE_1(1, 1),
    DEVICE_2(2, 2),
    DEVICE_3(2, 1);

    private final int generation;
    private final int deviceType;

    private CompanyXDevice(int generation, int deviceType) {
        this.generation = generation;
        this.deviceType = deviceType;
    }

    public int[] generateHistoricalData() {
        ...
    }

    ...
}
_

Company Xの実際のデバイスを実際に反映するデバイスでのみプレイすることが可能になりました。

2
Spotted

制約された方法で(おそらく他の言語の概念を適用して)「値」を考えているように見えます。

列挙できる値の種類についての考えを広げたらどうなるでしょうか。それは可能な用途の広い範囲を開きます。あなたのデザインの知恵は、あなたがその素晴らしい力で恐ろしいことをするのを防ぎます。

これを試して:

  • enumは、固定された値のセットを持つタイプにすぎないと考えてください。
  • enum値の概念を拡張して、Javaが許可するすべてのものに一致させます。
  • enumの拡張された概念を前提として、すべての設計の知恵を適用します。
1
Dale Emery