4

短くしてみます。

多くのインスタンス変数 (30 以上) を持つクラスがあるため、多くのゲッター/セッターがあります。クラス自体は単純ですが、getter/setter のために LOC が爆発しました (また、コードの重複が多すぎました)。

したがって、属性を削除して、次のようにマップに保存しました

public class MyTechnicalToolClassX
{

//...constructor

private Map<String, Object> data;

public Object getAttributeByKey(AttributeKey key)
{
    // ...doStuff, check data associated with key, etc
    // if (predicate == true) return otherData;
    return data.get(key.toString());
}

public void setAttributeByKey(AttributeKey key, Object value) throws IllegalArgumentException
{
    if(key.getType().isInstance(value))
    {
        data.put(key.toString(), value);
    }
    else
    {
        throw IllegalArgumentException("The passed value has the wrong type, we expect: "
        + key.getType().getName());
    }
}

public enum AttributeKey
{
    someKey1("key1", String.class),
    someKey2("key2", Date.class),
    //...
    someKeyN("keyN", SomeType.class);

    private String key;
    private Class valueType;

AttributeKey(String key, Class valueType)
{
    this.key = key;
    this.valueType = valueType;
}

@Override
public String toString()
{
    return key;
}

public Class getType()
{
    return valueType;
}

} // AttributeKey

} // MyTechnicalToolClassX

以前は AttributeKey は単なる文字列でしたが、この方法でセッターで型の安全性を確保できます。クラス内のコードの重複を削除しましたが、多くの属性を持つ他のクラスがあります (それらはいくつかの技術オブジェクトを表しているため...)。ここでの最善のアプローチは何ですか? すべてのクラスに独自の AttributeKey 列挙型を与えるには?

解決

さらにいくつかの考えを追加しました。コンパイル時にタイプセーフになりました。これが、ゲッターとセッターの新しいインターフェイスです。

public <Type, SetVal extends Type> void setAttributeByName(IAttribute<Key, Type> attribute, SetVal value);

public <Type> Type getAttributeByName(IAttribute<Key, Type> attribute);

Joshua Bloch は、こ​​の種の概念をtypesafe 異種コンテナーと呼んでいます。

4

2 に答える 2

8

OOP スクールで学んだことは忘れてください。

私たちは3年間で道を歩んできました。私たちは今、はるかに優れた言語を持っています。Swift、Rust、Kotlin、Go など。データ/値の型とそれを操作するコードの違いを理解しています。適切なエンタープライズ CLEAN アーキテクチャは、Java 領域でこれを推奨しています。しかし、Java はそのようなパターンを言語レベルでサポートしていません。その結果、RxJava や、コード生成を行う注釈プロセッサなどの (まだ素晴らしい) ものが多用されています。Kotlin は、Java が非常に最小限のコストで解決できない方法で Java の問題を解決する傾向があります。厳密なソース互換性の喪失 (Groovy ではありません)。

元の回答、下部に更新があります。

答えは 2 つあります。

1:

役に立たないボイラープレート!

クラスが大きなデータ オブジェクトを表す場合、ほとんどのメンバー変数は単なるデータのコンテナーのように思えます。このような場合、情報隠蔽の OOP 規則に厳密に従うことはあまり重要ではありません。人々はしばしばこの規則の目的を混同し、最終的にそれを悪用することになります。これは単に、プログラマーがオブジェクトの複雑で不必要な内部処理に対処する必要がないようにするためです。オブジェクト全体をマスクするのではなく、いじってはいけない部分だけをマスクします。単純にデータベースから情報をマッピングする場合、またはストレージ コンテナーとして機能する場合は、次のようなコードを実行します。

import java.util.Date;

public class Article {

    protected int id;

    protected String guid;
    protected String title;
    protected String link;
    protected Date pubDate;
    protected String category;
    protected String description;
    protected String body;
    protected String comments;
    
    protected Article (String articleTitle, String articleBody) {
        title = articleTitle;
        body = articleBody;
    }
    
    protected Article (String guid, String articleTitle, String articleLink,
            long publicationDate, String category, String description,
            String articleBody, String commentsLink) {
        this(articleTitle, articleBody);
        this.guid = guid;
        this.link = articleLink;
        this.pubDate = new Date(publicationDate);
        this.category = category;
        this.description = description;
        this.comments = commentsLink;
    }
    
    protected Article (int id, String guid, String articleTitle, String articleLink,
            long publicationDate, String category, String description,
            String articleBody, String commentsLink) {
        this(guid, articleTitle, articleLink, publicationDate, 
                category, description, articleBody, commentsLink);
        this.id = id;
    }

    protected int getId() {
        return id;
    }
    
    protected String getTitle() {
        return title;
    }

    protected String getGuid() {
        return guid;
    }

    protected String getLink() {
        return link;
    }

    protected String getComments() {
        return comments;
    }

    protected String getCategory() {
        return category;
    }

    protected String getDescription() {
        return description;
    }

    protected String getBody() {
        return body;
    }

    protected void setId(int id) {
        this.id = id;
    }

    protected void setGuid(String guid) {
        this.guid = guid;
    }

    protected void setTitle(String title) {
        this.title = title;
    }

    protected void setLink(String link) {
        this.link = link;
    }

    protected void setPubDate(Date pubDate) {
        this.pubDate = pubDate;
    }

    protected void setCategory(String category) {
        this.category = category;
    }

    protected void setDescription(String description) {
        this.description = description;
    }

    protected void setBody(String body) {
        this.body = body;
    }

    protected void setComments(String comments) {
        this.comments = comments;
    }

}

.. まったくおぞましい。

このような場合、データ オブジェクトのメンバーにアクセスするためだけに余分な作業を行う理由はまったくありません。特に、いくつかの外部コード行でそれらを使用している場合:

public OtherClass {

    private Article article;

    public OtherClass(Article data) {
        article = data;
    }
    
    public String getArticleContents() {

        return (new StringBuilder())
        .append(article.getTitle())
        .append(article.getCategory())
        .append(dateToString(article.getPubDate())
        .append(article.getBody())
        .toString();
    }
}

メンバーに直接アクセスするだけで、何百行ものコードを節約できます(あなたがやろうとしていたように)。

これは、この質問に対する 2 番目の回答につながります。

二:

デザインスタン..

コードが腐っている可能性があります。ラムジーシェフは恥ずかしいでしょう。理由は次のとおりです。

明らかに、上記の機能は、他の役に立たない不要な file-system-littering に含まれているのではなくOtherClass、クラスに配置できる (および配置する必要がある) ため、まったく役に立ちません。これを行うと、getterとsetter が必要であることさえ忘れることができます。それとインターフェースするものは、タイトルや本文などを個別に必要とするのではなく、記事の内容のみを必要とする場合があるためです。このアプローチでは、クラスは外部の世界からすべてを隠し、絶対に必要な情報のみを提供します。ArticleOtherClass OtherClassArticle

これらはあなたの問題に対する2つの完全に実行可能な答えであるため、解決策が必要 です

Clojure を使用する

オブジェクトのモデリング

オブジェクトをモデル化するためにクロージャを使用できますが、さらに優れたアプローチがあります。興味深いのは、関数を第一級市民として扱う言語では、従来のオブジェクト指向パラダイムを完全にマップを使用してモデル化できるということです。与えられた。

Articleこれを元の+OtherClassアプローチと比較します。

(defn Article []
  (let [id (atom nil)
        guid  (atom nil)
        title  (atom nil)
        link (atom nil)
        pubdate (atom nil)
        category (atom nil)
        description (atom nil)
        body (atom nil)
        comments (atom nil)

        set (fn [g t l p cg d b cm]
              (do (reset! guid g)
                  (reset! title t)
                  (reset! link l)
                  (reset! pubdate p)
                  (reset! category cg)
                  (reset! description d)
                  (reset! body b)
                  (reset! commments cm)))
        get (fn [] [@guid
                    @link
                    @description
                    @comments
                    :content (content)])

        content #(str title category pubdate body)]
    {:get get, :set set}))

この上の例は、両方の回答からポイントを取得し、それらを組み合わせて不要なメンバーを非表示にし、論理機能 (「コンテンツ」を取得する機能) を組み込み、信じられないほどの光沢のあるボイラープレートを必要としない言語を使用するシステムです。コード..

クラス/オブジェクト システムの置き換え

これは関数型言語でオブジェクトをモデル化する方法の良い例ですが、Clojure や関数型プログラミング全般にとって完全に慣用的なものではありません。構造化データをさらに簡単に作成する方法については、Clojure StructMaps and Recordsを参照してください。

2017年アップデート

Kotlinを使用するだけです。それは全面的に Java 病を治しています。これらすべてのことを第一級の言語でサポートしており、コンパイラは役に立たないボイラープレートを取り除くのにも役立ちます。それは 7 年以上前から存在しており、2016 年 2 月から安定したリリースになっています。最初に知っていたら、おそらく Closure を含めなかったでしょう。

于 2013-04-26T08:22:46.200 に答える
3

Lambokのようなものを探しているかもしれません。

于 2013-04-25T22:36:43.903 に答える