7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

流れるようなインターフェース?-良いコード書くきっかけを与えたい。3[C#リファクタリングサンプル]

Last updated at Posted at 2017-02-18

流れるようなインターフェースの使い方はこれで正しいのか?

ある現場でJava経験の長い人にC#のプロジェクトを手伝ってもらったことがある。その中で、流れるようなインターフェースを使用しているコードがあったがずっと納得がいかない部分があった。そのときのコードを参考にしてサンプルコードを作成してみた。

仕様)DBから取得した結果に対して画面の値をマージしてDB更新する。

  1. DBにはHeader1,Header2,Header3があり、全て更新対象とする。
  2. 画面で値編集可能であり、マージのタイミングは登録ボタンクリック時。
        /** メイン処理 **/
        private Dao _dao = new Dao();

        public void Main()
        {
            // DBから現時点の情報を取得する。
            var param = new UpdateParameter(_dao)
                            .SetHeader(1)
                            .SetHeader2("a")
                            .SetHeader3(2);

            // 画面の情報を反映する。
            SetValueFromView(param);

            // DBを更新する。
            _dao.Update(param);
        }

        private void SetValueFromView(UpdateParameter param)
        {
            // 画面の値を取得したパラメータのHeader1,2,3に反映する。
            // コードは省略
        }

        /** DB更新テーブルのDTOを一つにまとめたパラメータクラス **/
        public class UpdateParameter
        {
            public Header Header { get; private set; }
            public Header2 Header2 { get; private set; }
            public Header3 Header3 { get; private set; }

            private readonly Dao _dao = null;

            public UpdateParameter(Dao dao)
            {
                _dao = dao;
            }

            public UpdateParameter SetHeader(int id)
            {
                Header = _dao.GetHeader(id);
                return this;
            }

            public UpdateParameter SetHeader2(string code)
            {
                Header2 = _dao.GetHeader2(code);
                return this;
            }

            public UpdateParameter SetHeader3(int id)
            {
                Header3 = _dao.GetHeader3(id);
                return this;
            }
        }

        /** Header1,2,3のDTO **/
        public class Header
        {
            public int Id { get; set; }
        }

        public class Header2
        {
            public string Code { get; set; }
        }

        public class Header3
        {
            public int Id { get; set; }
        }

        /** データ取得、および更新用Dao **/
        public class Dao
        {
            public Header GetHeader(int id)
            {
                // ヘッダーの取得
                return new Header() { Id = id };
            }

            public Header2 GetHeader2(string code)
            {
                // ヘッダー2の取得
                return new Header2() { Code = code };
            }

            public Header3 GetHeader3(int id)
            {
                // ヘッダー3の取得
                return new Header3() { Id = id };
            }

            public void Update(UpdateParameter param)
            {
                // DB更新処理を実行する。コードは省略
            }
        }
java
    private Dao dao = new Dao();

    public void main() {
        // DBから現時点の情報を取得する。
        UpdateParameter param = new UpdateParameter(dao)
                .setHeader(1)
                .setHeader2("a")
                .setHeader3(2);

        // 画面の情報を反映する。
        setValueFromView(param);

        // DBを更新する。
        dao.update(param);
    }

    private void setValueFromView(UpdateParameter param) {
        // 画面の値を取得したパラメータのHeader1,2,3に反映する。
        // コードは省略
    }

    public class UpdateParameter {
        private Header header = null;
        private Header2 header2 = null;
        private Header3 header3 = null;

        private final Dao dao;

        public UpdateParameter(Dao dao) {
            this.dao = dao;
        }

        public UpdateParameter setHeader(int id) {
            this.header = dao.getHeader(id);
            return this;
        }

        public UpdateParameter setHeader2(String code) {
            this.header2 = dao.getHeader2(code);
            return this;
        }

        public UpdateParameter setHeader3(int id) {
            this.header3 = dao.getHeader3(id);
            return this;
        }

        public Header getHeader() {
            return header;
        }

        public Header2 getHeader2() {
            return header2;
        }

        public Header3 getHeader3() {
            return header3;
        }

    }

    /** Header1,2,3のDTO **/
    public class Header {
        private int id;

        public int getId() {
            return id;
        }

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

    public class Header2 {
        private String Code;

        public String getCode() {
            return Code;
        }

        public void setCode(String code) {
            Code = code;
        }

    }

    public class Header3 {
        private int Id;

        public int getId() {
            return Id;
        }

        public void setId(int id) {
            Id = id;
        }
    }

    /** データ取得、および更新用Dao **/
    public class Dao {
        public Header getHeader(int id) {
            // ヘッダーの取得
            Header header = new Header();
            header.setId(id);
            return header;
        }

        public Header2 getHeader2(String code) {
            // ヘッダー2の取得
            Header2 header2 = new Header2();
            header2.setCode(code);
            return header2;
        }

        public Header3 getHeader3(int id) {
            // ヘッダー3の取得
            Header3 header3 = new Header3();
            header3.setId(id);
            return header3;
        }

        public void update(UpdateParameter param) {
            // DB更新処理を実行する。コードは省略
        }
    }

気になったこと

UpdateParameterが流れるようなインターフェースになっているようなのだが、このコードには以下の問題がある。

  1. UpdateParameterがDaoを参照している。
  2. テーブルが増えたら直す箇所が複数ある。
  3. SetHeader1~SetHeader3を必ず呼び出さなければならない。

流れるようなインターフェースはStringBuilderのようなクラスだと利点が理解できる。一方、UpdateParameterのような単純な情報を持つだけのクラスで使うと違和感がある。

無難なコードに直してみる。

UpdateParameterのDao参照を削除して、メイン処理側でDB取得するようにしただけであるが、このコードなら納得できる。

       /** メイン処理 **/
        private Dao _dao = new Dao();

        public void Main()
        {
            // DBから現時点の情報を取得する。
            var param = new UpdateParameter();
            // メイン処理でDBからデータを取得する。
            param.Header = _dao.GetHeader(1);
            param.Header2 = _dao.GetHeader2("a");
            param.Header3 = _dao.GetHeader3(2);

            // 画面の情報を反映する。
            SetValueFromView(param);

            // DBを更新する。
            _dao.Update(param);
        }

        private void SetValueFromView(UpdateParameter param)
        {
            // 画面の値を取得したパラメータのHeader1,2,3に反映する。
            // コードは省略
        }

        /** DB更新テーブルのDTOを一つにまとめたパラメータクラス **/
        public class UpdateParameter
        {
            public Header Header { get; set; }
            public Header2 Header2 { get; set; }
            public Header3 Header3 { get; set; }

            // Daoの参照を削除
        }

        /** Header1,2,3のDTO **/
        public class Header
        {
            public int Id { get; set; }
        }

        public class Header2
        {
            public string Code { get; set; }
        }

        public class Header3
        {
            public int Id { get; set; }
        }

        /** データ取得、および更新用Dao **/
        public class Dao
        {
            public Header GetHeader(int id)
            {
                // ヘッダーの取得
                return new Header() { Id = id };
            }

            public Header2 GetHeader2(string code)
            {
                // ヘッダー2の取得
                return new Header2() { Code = code };
            }

            public Header3 GetHeader3(int id)
            {
                // ヘッダー3の取得
                return new Header3() { Id = id };
            }

            public void Update(UpdateParameter param)
            {
                // DB更新処理を実行する。コードは省略
            }
        }

java
    private Dao dao = new Dao();

    public void main() {
        // DBから現時点の情報を取得する。
        UpdateParameter param = new UpdateParameter();
        // メイン処理でDBからデータを取得する。
        param.setHeader(dao.getHeader(1));
        param.setHeader2(dao.getHeader2("a"));
        param.setHeader3(dao.getHeader3(2));

        // 画面の情報を反映する。
        setValueFromView(param);

        // DBを更新する。
        dao.update(param);
    }

    private void setValueFromView(UpdateParameter param) {
        // 画面の値を取得したパラメータのHeader1,2,3に反映する。
        // コードは省略
    }

    public class UpdateParameter {
        private Header header = null;
        private Header2 header2 = null;
        private Header3 header3 = null;

        // Daoの参照を削除

        public void setHeader(Header header) {
            this.header = header;
        }

        public void setHeader2(Header2 header2) {
            this.header2 = header2;
        }

        public void setHeader3(Header3 header3) {
            this.header3 = header3;
        }

        public Header getHeader() {
            return header;
        }

        public Header2 getHeader2() {
            return header2;
        }

        public Header3 getHeader3() {
            return header3;
        }

    }

    // 以下のコードは省略

まとめ

Javaの開発経験は1年程度なので、Javaだとサンプルであげたようなコードは普通なのか気になるところ。
また、「気になったこと」に記載した問題点をそのままにしてでも、流れるようなインターフェースを使う理由はなんだろう。

[前の記事(ちょっと気になるコード集)]
(http://qiita.com/csharpisthebest/items/7d9d2c7e4da4b89488fd)

[次の記事(冗長な代入文)]
(http://qiita.com/csharpisthebest/items/f9ebc741e40037553d5b)

目次

7
7
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?