トップ回答者
Interfaceの多重実装はできませんか?

質問
-
お世話になります。同一クラスに対して同じインターフェースを複数実装することはできないでしょうか?
ちょっと意味不明だと思いますのでコードを載せます。
public partial class Form1 : Form, IInsertAction, IUpdateAction, IDeleteAction { public Form1() { InitializeComponent(); } //ここにそれぞれ以下の感じで実装したい void IInsertAction.Initialize() { //DoSomething } void IUpdateAction.Initialize() { //DoSomething } } interface IAction { void Initialize(); bool Read(); bool Regist(); } interface IInsertAction : IAction { } interface IUpdateAction : IAction { } interface IDeleteAction : IAction { }
○実現したいこと
・モード(Insert,Update,Delete)の遷移をフォームから分離して管理したい。
・各モードのアクション内容は、フォームのコントロールなどを大量に操作するので別クラスに分けてプロパティなどで渡したくない。
トリッキーなやり方だと思いますが、もっといい手が浮かばず悩んでおります。
アドバイスなどありましたらよろしくお願いします。
VS2010SP1 & C# 4.0 .NET 4.0, Windows.Forms にて作成しています。
以上、よろしくお願いします。
回答
-
解決されたようですが、自分の投稿について、誤り訂正があるので。(文章を作っている時間と、投稿している時間は一致していないので。)
明示実装ならできるかな、と思ったのですが、継承元の IAction のメソッドとして実装されてしまいますね。
これは、考えてみれば当たり前のように思います。IInsertAction は、IAction でもあります。ご要望は、「IInsertAction.Initialize と、IAction.Initialize を、別々に実装したい」ということを含んでいます。それがおかしな要望であることは、おわかりいただけると思います。IInsertAction, IUpdateAction 等にそれぞれ同名メソッドを定義すれば行けますが、それではダメ?
IInsertAction 等で、全てのメソッドを new で再定義し直すという方法があるのだけれど、そうすると IAction のメソッドを実装していないことになってしまいます。
実装の業務イメージとしまして、例えばマスタメンテ画面などを想定しています。
操作の基本的なアクションは同じとし、コーディング時には各アクションの中を穴埋め実装をさせたいと考えています。ちょっと、イメージできません。ここで定義しようとされている「挿入動作」「更新動作」「削除動作」という操作の塊は、データに対して必要なものではないでしょうか。データを見せるフォームに対して必要なものとしては、「挿入可能状態であることがわかるようにする」「更新可能状態であることがわかるようにする」の様なものでしょうか。もっとも、「挿入動作を初期化する」という操作は、データに関しても不要なように思います。もう少し、分析を進めてみてはいかがでしょうか。
あるいは、仕様として定義するべき物を、コーディングで定義しようとしているように思います。これでは、行き当たりばったりになってしまうと思います。
うーん、Form に実装させる物としては、「モードが変えられる」というインタフェースがあって、「モードが変えられる」ためには、「モードを変更する(モード)」という操作、「対応した動作を行う(モード)」という操作があればいいのではないでしょうか。モードは列挙体で管理できると思います。
Jitta@わんくま同盟
すべての返信
-
class Form1 : Form { private TextBox TextBox1; public IInsertAction AsInsert() { return new InsertAction(this); } private class InsertAction : IInsertAction { private Form1 m_owner; public InsertAction(Form1 owner) { this.m_owner = owner; } public void Initialize() { this.m_owner.TextBox1.Text = "Insert"; } } }
こんなのかしら。
- 編集済み Hongliang 2013年11月20日 8:27 メソッド名がおかしかった
-
今一歩、taritariさんのやりたいことがわからないです。インターフェースをどのような目的で使用されているのかもわかりません。
>・モード(Insert,Update,Delete)の遷移をフォームから分離して管理したい。
とのことですが、モードの切り替えロジックが別にあるのであれば、Form1はむしろそのロジックを与えてもらう立場のようにも取れますが、これはちょっと現実的じゃないですよね。
フォームを管理するクラスがあって、そこに渡して管理するのであれば、やはりForm1が何らかのインターフェースを継承していなければなりませんし・・・。(dynamic型でも代用できますが・・・)Hongliangさんの回答で良いのかもしれませんが、モードが変ると別のインスタンスになります。これもこれで良いのかもしれませんが、やはりtaritariさんの実現されたいことがもう少しわからないので、いろいろと判断できずにいます。
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
- 編集済み trapemiyaModerator 2013年11月20日 15:29 Hongliangさんの綴りで大文字小文字が間違っていたので修正。すみませんでした。
- 回答の候補に設定 星 睦美 2013年11月22日 4:20
-
皆様返信ありがとうございます。
目的をしっかりと書くべきでした。申し訳ありません。
○各フォームの基本的なアクションを固定化したい
○フォーム内のコードは別クラスに切り出し不可
○フォーム実装者にシステム的に制限をかけ、独自のコーディングを避けたい
以上の目的から以下のような考えでおります。・モードの遷移を管理するクラスを用意してクラス化
・フォームにインターフェースを実装させることで別クラスを作成せずに機能を実装できるのでは?
・インターフェースを実装させて実装を強制化
という意図でいます。
これに『モード管理クラスでは各モードを統一的に扱いたい』という希望がありまして(IAction化)、前述のようになっています。
実装の業務イメージとしまして、例えばマスタメンテ画面などを想定しています。
操作の基本的なアクションは同じとし、コーディング時には各アクションの中を穴埋め実装をさせたいと考えています。
こういった業務は一般的に多いと思うのですが、みなさんどういった実装をされているのでしょうか?
以上、よろしくお願いします。
-
自己レスです。
Jitta様の意見を元にデリゲートで実装しようと考えましたが、強制するためにインターフェースを使用するのは何か間違えている気がして考えなおしました。
その結果、コンポーネントでイベントにすることで実現することにしました。
フォームにModeActionコンポーネントを3つ貼り付け、イベントハンドラを割り当てて使用します。
public partial class Form1 : Form { private ModeActionController ac; private void Form_Load(object sender, EventArgs e) { ac = new ModeActionController(insertMode, updateMode, deleteMode); } private void btnFunction_Action(object sender, FunctionKeyEventArgs e) { switch (e.Key) { case FunctionKeys.F01: ac.Mode = EditMode.Insert; break; } } } public class ModeAction : Component { public event EventHander Initialize; protected virtual OnInitialize(EventArgs e) { if (Initialize != null) Initialize(this, e); } internal void InitializeAction() { OnInitialize(); } } public class ModeActionController { private readonly ModeAction insertMode; private readonly ModeAction updateMode; private readonly ModeAction deleteMode; public ModeActionController(ModeAction insertMode, ModeAction updateAction, ModeAction deleteAction) { this.insertMode = insertMode; this.updateMode = updateMode; this.deleteMode = deleteMode; } private EditMode mode = EditMode.Initialze; public EditMode Mode { get { return mode; } set { mode = value; GetMode(mode).InitializeAction(); } } private ModeAction GetMode(EditMode mode) { ModeAction m = null; switch (mode) { case EditMode.Insert: m = insertMode; break; case EditMode.Update: m = updateMode; break; case EditMode.Delete: m = deleteMode; break; } if (m == null) m = new ModeAction(); return m; } }
今回はこれを採用することにします。
皆さん貴重なご意見ありがとうございました。
-
解決されたようですが、自分の投稿について、誤り訂正があるので。(文章を作っている時間と、投稿している時間は一致していないので。)
明示実装ならできるかな、と思ったのですが、継承元の IAction のメソッドとして実装されてしまいますね。
これは、考えてみれば当たり前のように思います。IInsertAction は、IAction でもあります。ご要望は、「IInsertAction.Initialize と、IAction.Initialize を、別々に実装したい」ということを含んでいます。それがおかしな要望であることは、おわかりいただけると思います。IInsertAction, IUpdateAction 等にそれぞれ同名メソッドを定義すれば行けますが、それではダメ?
IInsertAction 等で、全てのメソッドを new で再定義し直すという方法があるのだけれど、そうすると IAction のメソッドを実装していないことになってしまいます。
実装の業務イメージとしまして、例えばマスタメンテ画面などを想定しています。
操作の基本的なアクションは同じとし、コーディング時には各アクションの中を穴埋め実装をさせたいと考えています。ちょっと、イメージできません。ここで定義しようとされている「挿入動作」「更新動作」「削除動作」という操作の塊は、データに対して必要なものではないでしょうか。データを見せるフォームに対して必要なものとしては、「挿入可能状態であることがわかるようにする」「更新可能状態であることがわかるようにする」の様なものでしょうか。もっとも、「挿入動作を初期化する」という操作は、データに関しても不要なように思います。もう少し、分析を進めてみてはいかがでしょうか。
あるいは、仕様として定義するべき物を、コーディングで定義しようとしているように思います。これでは、行き当たりばったりになってしまうと思います。
うーん、Form に実装させる物としては、「モードが変えられる」というインタフェースがあって、「モードが変えられる」ためには、「モードを変更する(モード)」という操作、「対応した動作を行う(モード)」という操作があればいいのではないでしょうか。モードは列挙体で管理できると思います。
Jitta@わんくま同盟
-
>IInsertAction, IUpdateAction 等にそれぞれ同名メソッドを定義すれば行けますが、それではダメ?
それも考えたのですが、モード管理側(ModeActionController)で現在のモードに対して一括して操作を行いたかったのです。
(前述のソースではModeプロパティで現在のモードに対してInitializeAction()をかけている感じです)
>モードに関して
ご指摘の内容を元に検討してみたところ、確かにまだまだ分析が甘かったようです。
ただ、モードを列挙体で管理するとなると、各モードの実行(例えばInitialize())を内部でモード判定する処理が入りますよね。
それは避けたい事態で、なるべくなら各モードを分断してそれぞれのメソッドにしたかったのです。
それとModeActionの定義がおかしかったようです。
このクラスはデータに対する操作を行うクラスではなく、ユーザー操作に対して、として命名していました。
思えばイベントと同じような気がします。
例えば、各モードに定義するアクションは以下のとおりです。
・初期化 ・登録 ・クリア
うん、今さらながら、イベントという方がしっくりきます。
ModeActionControllerはモードを管理して、現在のモード(列挙体)の管理とそれぞれのモードのイベントを発行するクラス、ということになりそうです。
とても参考になりました。
丁寧な対応、ありがとうございました。