C#手遊び(抽象クラスとかinterfaceとか使ってみた)

#この記事、何?
昔から難しそうだな、でも便利そうだな、使いこなせるとかっこいいと思ってた抽象クラスとかinterfaceとか。
で、いい機会に恵まれたので復習の意味でミニマムコードチックなものを作ってみた。

#どういう人向け?
どうだろう。正直自分あて。自分の復習のため。
一応、ペタッと張ってそのまま動くはずなので、よければどうぞ。
文末に書いたけど、学ぶとき、手元に動くものがあっていじってみるとはかどるよ～

・・・というか、「こう書いたらいいのに」という、ご教授あればお願いします。
(正直、ついこの前初めてinterfaceとかabstractとか書いた。何か凄く間違ってるかも。。。)

#試した環境は?
Windows 8 Pro
.net framework 4.0
(C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe)


#コンパイル
いつもの。
お勉強用としてはVisual Studioのコード補完(補助輪)は強すぎるのでVisual Studio Codeかサクラエディタで。

■C#手遊び(Compiler w/o Visual Studio)
https://qiita.com/siinai/items/8a325ad4eade1a2f6e9e

#試しに作ろうとしたもの
この手のことでよくある、「動物」とか、「人」とか、「犬」・「猫」とかってやってもな・・・と思ってた。
正直、今回書くまで、そういう記事を読んでも自分の中に入ってこないの。
説明する側からするとベストな選択なんだけど、わかろうと思っている人(=わかってない人)からするとピンとこない。
・・・いや、あたしが分かろうとしてないだけだったってことかもしれないけど。

なので、わかった(つもり)のことをOutputするために、こんなのでやってみた。

<方針>
いま、画面を作っている。TextBox, ComboBox, ListBoxがある。
それ以外にコントロールA,コントロールBがあって、それぞれ不可視のオブジェクト(クラス)に値を置いておく。
それらをまとめて一つのList<何か>に集めて、foreachでGetValue()をくるくるっと呼び出したい。

なので、GetValue()を持つinterfaceを定義する。
foreachしたい対象とinterface両方を継承したExなどを作ってそれぞれにinterfaceを継承させる。
これでGetValue()が存在することを保証させられる。
だから、List<そのinterface>で集められるからforeachでくるくるできる。

##抽象クラス
interfaceのままだと呼び出し方と戻り値などを定義するだけで、歴の数を返すという「具体的な形」を入れられない。
最終的にnewして具象クラスを作るときにオブジェクトを作るとしても、その手前で決めておいてもいいことは決めておきたい。
逆に、だったら普通にクラスでいいじゃん、って話だけど、普通のクラスにしてしまうと、直接それをnewできてしまう。
似ているけどちょっと違うものを作りたいとき、その最大公約数として「普通のクラス」を作ったのに、コーディングミスでそれをnewされても困るときに使うといい?

#interface
自分のイメージとしてはFunc<T, T, T>とかして名前を与えただけのものを束ねたもの。
具体的な処理の内容とか、値とかは持たない。(持たせない)
だからこそ、C++とかで問題になる多重継承問題が発生しない。(菱形見たくない。。)



#できたもの

```csharp
using System;
using System.Collections.Generic;

public class test28_02
{
    private static List<ICommon> controls = null;

    public static void Main(string[] args)
    {
        string ret = "";

        //起動時の初期処理の代わり
        Init();

        //・・・何らかの処理で値が変わっている(ということにする)

        //各設定値の取得
        foreach (var item in controls)
        {
            ret += item.GetValue() + "\n";
        }

        Console.WriteLine(ret);

    }

    public static void Init()
    {
        //TextBoxEx, ComboBoxEx, ListBoxExと HistoryA, HistoryBを設定
        controls = new List<ICommon>();
        controls.Add(new TextBoxEx());
        controls.Add(new ComboBoxEx());
        controls.Add(new ListBoxEx());
        controls.Add(new HistoryA());
        controls.Add(new HistoryB());
    }
}

public class TextBox  { } //System.Windows.Forms.Form.TextBox  の代役 }
public class ComboBox { } //System.Windows.Forms.Form.ComboBox の代役 }
public class ListBox  { } //System.Windows.Forms.Form.ListBox  の代役 }

public interface ICommon
{
    string GetValue();
}

//履歴を保持して最新を返すという抽象クラス
public abstract class ChangedHistory
{
    public bool isChanged = false;
    public List<string> list = new List<string>();
    public abstract void SetChangedData(string arg);
    public int GetHistCnt() { return list.Count; }
}

//「何かA」の変更履歴を管理するクラス (※このサンプルではA/B同型だけどホントは異なるつもりで。)
public class HistoryA : ChangedHistory, ICommon
{
    public override void SetChangedData(string arg)
    {
        isChanged = true;
        list.Add(arg);
    }

    public string GetValue()
    {
        string ret = "HistoryA:";
        if (isChanged)
        {
            ret = list[list.Count - 1];
        }
        return ret;
    }
}

//「何かB」の変更履歴を管理するクラス (※このサンプルではA/B同型だけどホントは異なるつもりで。)
public class HistoryB : ChangedHistory, ICommon
{
    public override void SetChangedData(string arg)
    {
        isChanged = true;
        list.Add(arg);
    }

    public string GetValue()
    {
        string ret = "HistoryB:";
        if (isChanged)
        {
            ret = list[list.Count - 1];
        }
        return ret;
    }
}

//TextBoxから値を取得するクラス
public class TextBoxEx : TextBox, ICommon
{
    public string GetValue()
    {
        string ret = "TextBoxEx:";
        //ret = TextBoxから値を取得
        return ret;
    }
}

//ComboBoxから値を取得するクラス
public class ComboBoxEx : ComboBox, ICommon
{
    public string GetValue()
    {
        string ret = "ComboBoxEx:";
        //ret = ComboBoxから値を取得
        return ret;
    }
}

//ListBoxから値を取得するクラス
public class ListBoxEx : ListBox, ICommon
{
    public string GetValue()
    {
        string ret = "ListBoxEx:";
        //ret = ListBoxから値を取得
        return ret;
    }
}


```

(コンパイルと実行結果)
コンパイラが何か言っているけど気にしない方向で。。。

```
C:\projects\qiita\draft\28>C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe test28-02.cs
Microsoft (R) Visual C# Compiler version 4.7.3062.0
for C# 5
Copyright (C) Microsoft Corporation. All rights reserved.

This compiler is provided as part of the Microsoft (R) .NET Framework, but only supports language versions up to C# 5, w
hich is no longer the latest version. For compilers that support newer versions of the C# programming language, see http
://go.microsoft.com/fwlink/?LinkID=533240


C:\projects\qiita\draft\28>test28-02.exe
TextBoxEx:
ComboBoxEx:
ListBoxEx:
HistoryA:
HistoryB:

```


#感想
まあ面白かった。
正直、これを書く前、初めてabstractとかinterfaceとか書いた時が、もう、すごく、なんか、こう、という感じだった。
みんなこんな知識を前提に何年も前からプログラム書いているのか・・・と思うと、もったいないというか、悔しいというか。。。