web-dev-qa-db-ja.com

静的クラスを継承できない/許可されない場合の良い習慣は何ですか

私はC#でプロジェクトを開発していますが、設計上の理由により、静的クラスに別の静的クラスを継承させることはできません。しかし、私の意見では、これが理にかなっているケースがあります。

ローカルファイル、YouTube、SoundCloud、Jamendoなど、さまざまな音楽ソースから音楽を再生できる音楽プレーヤーを持っています。現在、これらのソースごとに、トップトラックの取得、検索などの静的メソッドを持つ1つの静的クラスがあります。トラックなど.

当然、多くのコードがこれらすべてのクラスで共有されているため、すべての一般的なコードをリファクタリングして、より一般的なMusicSourceクラスに入れたいと思いました。しかし、C#ではそれができません。

ここでのベストプラクティスは何でしょうか?冗長なコードをすべて削除して、新しい音楽ソースを簡単に作成できるようにしたいと考えています。

4

これらの「ミュージックソース」クラスは、静的でないクラスのように聞こえ、たった1つのインスタンスしか必要としません。それらは2つの異なるものです!

これらを非静的にする理由は次のとおりです。

  • それらが何らかの内部状態を持っている(または最終的に持っている可能性がある)場合。例えばキャッシュされたログイン資格情報、または上位10トラックのキャッシュされたリスト。ステートフル静的クラスは悪い考えです!彼らは基本的にシングルトンの貧弱な実装です。
  • 多くの音楽ソースを使用する場合は、それらすべてに対していくつかのアクションを実行することをお勧めします。例えば任意のソースから特定のトラックを見つけます。静的クラスでは、クラスごとに行が必要になります。非静的クラスがある場合は、それらのコレクションをループするだけです。

すばらしい答えがあります here これは、より多くの理由を提供し、より詳細に説明します。

16
vaughandroid

「設計上の決定」に関係なく、(少なくともC#では)静的クラスをまったく継承できません。

おそらく、質問を言い換える必要がありますが、この不自然で非常に単純な例のように、静的でないクラスを使用することはできません。

abstract class MusicSource 
{  
    abstract MusicData LoadMusic(string source);

    protected string SomeCommonProperty { get; set; }
}

class JamendoSource : MusicSource 
{   
    override MusicData LoadMusic(string source)
    {
        // Jamendo-specific code
    }
}
3
RJ Lohan

この場合のstaticの使用は完全に間違っています。人々は静的の方法を頻繁に使用する傾向があります!基本的に、1つの「MusicPlayer」とXの実装量(youtubeなど)があります。そのため、最初に頭に浮かぶのは継承です。

それらはすべて同じことを行いますが、少し異なる=>継承。アプリケーション自体を適応させる必要なしに、アプリケーションをいくつかの種類のソースと連携させたい=>継承/インターフェイスの分離。

静的クラスは便利かもしれませんが、この場合、Musicクラスがアプリケーションのコアであると感じています...削除するため、静的クラスでコア機能を構築しないでください。 ...

あなたは言う:

冗長なコードをすべて削除して、新しい音楽ソースを簡単に作成できるようにしたいと考えています。

ここでも、継承が中心です...

C#では、静的クラスを使用するたびに継承を忘れます。逆に、継承が必要なときはいつでも、静的クラスを忘れます。

とにかく最初にそれらを静的にしたのはなぜですか?

使用可能なインスタンスを1つだけにする場合は、それをシングルトンにします。そうでない場合は、それを非静的にしてください!

1
Frederik P.

誰かがこのトピックにまだ興味があるかどうかはわかりませんが、まもなく私は以下を試しました。おそらくそれは、いくつかの静的な動作を伴う一般的なソリューションの1つの方法です。

  public abstract class StructureItem {
        public int index = 0;
    }

    public abstract class StructureItem<T> : StructureItem where T : StructureItem
    {
        public static List<T> Elements = new List<T>();
    }

    public class TEST1 : StructureItem<TEST1>
    {
        public TEST1()
        {
            StructureItem a = this;
            this.index = 1;
            TEST1.Elements.Add(this);
        }
    }

    public class TEST2 : StructureItem<TEST2>
    {
        public TEST2()
        {
            StructureItem a = this;
            this.index = 2;
            TEST2.Elements.Add(this);
        }
    }

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            var test1 = new TEST1();
            var test2 = new TEST2();

            List<StructureItem> aList = new List<StructureItem>();

            aList.Add(test1);
            aList.Add(test2);

            Console.WriteLine("all Elements:");
            foreach (var item in aList)
            {
                Console.WriteLine("Element " + item.index);
            }
            Console.WriteLine("TEST1 Elements:");
            foreach (var item in TEST1.Elements)
            {
                Console.WriteLine("Element "+item.index);
            }
            Console.WriteLine("TEST2 Elements:");
            foreach (var item in TEST2.Elements)
            {
                Console.WriteLine("Element " + item.index);
            }

        }
    }

出力:

all Elements:
Element 1
Element 2
TEST1 Elements:
Element 1
TEST1 Elements:
Element 2
1
ecn