63116
あるコレクションに属する要素の取扱い方がよく分かっておりません。

例えば、以下の様なクラスとインスタンスがあったとします（説明のための例であり、実際には団体や、人である事はありません）。

```

    団体クラスのH協会インタンス
      ├ 所属人コレクション<人間クラス>
      │  └Zさんインスタンス
      ├ 反映メソッド（人間クラス）
      └ 編集メソッド（int）
    
    人間クラスのZさんインスタンス
      ├ 所属者id =1 
      ├ 名前 = "ZZ"
      ├ 特技 = "ドラゴンダイブ"
      └ 取り込みメソッド（人間クラス）
    
```

ここで、Zさんインスタンスのプロパティを編集する画面を用意するとき、各プロパティを編集可能にし、その変更内容を反映、破棄できるようにすると、どのような振る舞いをどのクラスでさせたらよいか、今一分かりません。

現状では、

①編集画面のコントローラに、Zさんインスタンスのクローン（以下Z2）を渡し、双方向バインディングさせる。  
②ボタン「反映」を押下するとH協会インスタンスの反映メソッドにZ2を送り実行する。  
または、ボタン「破棄」を押下したらZ2を破棄し終了  
③案1:H協会インスタンスの反映メソッドはZさんインスタンスを除外し、Z2を同じ場所におさめる。  
③案2:H協会インスタンスの反映メソッドはZさんインスタンスの取り込みメソッドで、Z2のプロパティを自身に反映させるよう指示する。

としています。  
案1も案2も、クローンをバインディングさせる事も不自然に思います。  
こういう場合はどのようなやり方が適切なのか、ご教授いただけると助かります。  
一応、作っているものはデスクトップアプリケーション、言語はc#やjavaを使用しておりますが、どの言語でも構いません。  
以上、よろしくお願いいたします。
CC BY-SA 4.0
2020-02-13T03:57:33.607
63017
2020-02-17T09:43:52.850
2020-02-17T02:31:10.660
37811
37811
question
java c#
コレクションの要素の編集、反映、破棄
はじめまして、こんにちわ。

環境によりますが、Javaでウェブやアプリなどの開発に絞れば、人や組織を表す項目のインスタンスが「反映」などの  
メソッドを持つことはあまり一般的ではありません。

こうした項目は通常`POJO`と呼ばれるオブジェクトで表され値の保持と、値へのアクセス以外の機能は持ちません。項目へのアクセスはモデルクラスに設けたをメソッドを介して、コントローラーやビューから行います。一般的な、MVC2モデルの実装方法ですね。

ですので、私がするのであればオブジェクト操作用のクラスを作り、そこでオブジェクトを編集する機能を集中します。

双方向バインドなどにも触れられているので、具体的な環境があるかと思われます。  
WEBなのかゲームなのか、フレームワークはどうなのか、もしくは何を作りたいのか、など詳細をいただければ、より具体的な回答が、得られるかもしれません。
CC BY-SA 4.0
2020-02-13T05:42:47.187
63018
2020-02-13T05:42:47.187
37777
63017
answer
基本的な説明自体はKouki.Wさんの通りです。  
例えば以下のようになるかと思います。

```

    public class Organization
    {
        public List<Person> Members { get; set; }
    }
    
    public class Person
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public List<Skill> Skills { get; set; }
    }
    
    public class OrganizationService
    {
        public Organization Organization { get; }       
    
        public OrganizationService(Organization organization)
        {
            this.Organization = organization;
        }
    
        public Result RegisterPerson(Person person)
        {
            if (!this.ValidatePerson(person)) return new Result(false);
    
            var found = this.Organization.Members.Find(p => p.Id = person.Id);
            if (found != null)
            {
                // 更新する
    
            }
            else
            {
                // 追加する
            }
            return new Result(true);
        }
    
        private bool ValidatePerson(Person person)
        {
            // 業務仕様に準じた登録可能なpersonの条件を満たしているか
            // 場合によってはOrganizationクラスが同名のメンバを持っていてそれを呼び出すだけかも。
        }
    }
    
    public partial class PersonEditForm : Form {
        // ...
    
        btnRegister_Click(object sender, EventArgs e)
        {
            var srvOrganization = new OrganizationService(this.organizationRef);
            srvOrganization.RegisterPerson(this.personRef);
        }
    }
    
```

※  
根本的な話を言うと、  
「組織画面に入り、その組織のメンバーを選択し、メンバー編集画面に移動する」というUI仕様がかなり異質な感じはします  
一般的な基幹業務であれば、ユーザはユーザマスタ一覧>編集、組織は組織マスタ一覧>編集で管理するイメージが強く、ユーザマスタ画面からダイレクトにユーザテーブル、ユーザ所属テーブル、ユーザ権限テーブルなどを更新するイメージが強いためです。
CC BY-SA 4.0
2020-02-13T17:04:56.027
63028
2020-02-13T17:04:56.027
25396
63017
answer
よりクリーンにするには、編集用の Person クラスと保存用の Person クラスを別に用意すると良いと思います。(関心の分離)  
編集関数は引数として編集用 Person クラスを取り、内部に保存用 Person クラスとして保存します。

編集画面の要素や構造は後々変更したいと思うかもしれませんし、保存方法も CSV から RDBMS に変更されたりするかもしれません。  
その時に片方の変更に引きずられて連鎖的にもう片方の実装も修正しなければならなくなる可能性があります。別クラスにしておけば変換部分を修正するだけで済みます。

もっとも変換部分を書くのもコード量が増えるので、小さなプロジェクト/モジュール内に留まると確信できるなら必ずしも分離する必要はないと個人的には思います。

```

    class EditablePerson
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
    class StoreablePerson
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
    
    interface IOrganizationService
    {
        void RegisterPerson(EditablePerson person);
    }
    
    class OrganizationService : IOrganizationService
    {
        readonly List<StoreablePerson> persons = new List<StoreablePerson>();
    
        public void RegisterPerson(EditablePerson person)
        {
            // validate
    
            var found = persons.Find(x => x.Id == person.Id);
            if (found != null)
            {
                found.Name = person.Name;
            }
            else
            {
                persons.Add(new StoreablePerson
                {
                    Id = person.Id,
                    Name = person.Name
                });
            }
        }
    
    }
    
```
CC BY-SA 4.0
2020-02-17T09:43:52.850
63116
2020-02-17T09:43:52.850
20885
63017
answer