6

ジェネリック メソッド シグネチャの使用方法を学習するために、次のコード例を作成しました。

Customer と Employee の両方のDisplay() メソッドを取得するために、実際にIPerson インターフェイスPerson 抽象クラスに置き換え始めました。

しかし、ボブおじさんがスコット・ハンセルマンに、それぞれが特定のことを行う小さなクラスをたくさん持つべきであるという単一責任の原則について話していたポッドキャストを思い出して、私は立ち止まりました。 ()およびCalculateSalary()メソッドを使用しますが、CustomerPrinter クラスCustomerSaver クラスCustomerSalaryCalculatorクラスが必要です。

それはプログラミングの奇妙な方法のようです。ただし、インターフェースを取り除くことも間違っていると感じたので (非常に多くの IoC コンテナーと DI の例がそれらを本質的に使用しているため)、単一責任の原則を試してみることにしました。

したがって、次のコードは、私が過去にプログラムしたものとは異なります(Display() メソッドを使用して抽象クラスを作成し、インターフェイスを削除したはずです) が、デカップリングと SOLID 原則について聞いたことに基づいて、この新しいコーディングの方法 (インターフェイスと PersonDisplayer クラス) これが正しい方法だと思います

他の人がこの問題について同じように考えているかどうか、またはこれのプラスまたはマイナスの影響を経験したかどうかを聞きたいです (たとえば、それぞれが特定のことを行う扱いにくい数のクラスなど)。

using System;

namespace TestGeneric33
{
    class Program
    {
        static void Main(string[] args)
        {
            Container container = new Container();
            Customer customer1 = container.InstantiateType<Customer>("Jim", "Smith");
            Employee employee1 = container.InstantiateType<Employee>("Joe", "Thompson");
            Console.WriteLine(PersonDisplayer.SimpleDisplay(customer1));
            Console.WriteLine(PersonDisplayer.SimpleDisplay(employee1));
            Console.ReadLine();
        }
    }

    public class Container
    {
        public T InstantiateType<T>(string firstName, string lastName) where T : IPerson, new()
        {
            T obj = new T();
            obj.FirstName = firstName;
            obj.LastName = lastName;
            return obj;
        }
    }

    public interface IPerson
    {
        string FirstName { get; set; }
        string LastName { get; set; }
    }

    public class PersonDisplayer
    {
        private IPerson _person;

        public PersonDisplayer(IPerson person)
        {
            _person = person;
        }

        public string SimpleDisplay()
        {
            return String.Format("{1}, {0}", _person.FirstName, _person.LastName);
        }

        public static string SimpleDisplay(IPerson person)
        {
            PersonDisplayer personDisplayer = new PersonDisplayer(person);
            return personDisplayer.SimpleDisplay();
        }
    }

    public class Customer : IPerson
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Company { get; set; }
    }

    public class Employee : IPerson
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int EmployeeNumber { get; set; }
    }
}
4

5 に答える 5

8

私は、単一責任の原則を職務の分離の実装と考えるのが好きです。皆さんのようにクラスを分割する前に、各クラスが何を担当すべきかを考えてみます。

あなたのクラスは非常に単純で、あなたが言及したように、実装されたPrint()機能Save()を持つ抽象クラスに適しています。私はあなたの現在のものよりもそのデザインを維持する傾向があります.

ただし、印刷と保存がさまざまな方法で実行される可能性のあるより複雑なタスクである場合は、その責任がより複雑になるため、専用PrinterまたはSaverクラスが保証されます。新しいクラスを作成するための「複雑さ」のしきい値は非常に主観的であり、正確な状況に依存しますが、最終的には、コードは私たち人間が理解するための抽象化にすぎないため、最も直感的になるようにしてください.

あなたContainerのクラスは少し誤解を招くものです。実際には何も「含まれていません」。これは実際にFactory Method Patternを実装しており、Factory という名前を付けることでメリットが得られます。

また、PersonDisplayerインスタンス化されることはなく、静的メソッドを介してすべての機能を提供できるため、静的クラスにしないのはなぜですか? プリンターやセーバーなどのユーティリティ クラスが静的であることは珍しくありません。異なるプロパティを持つプリンターの個別のインスタンスを用意する必要がない限り、それを静的に保ちます。

于 2009-03-18T17:39:10.517 に答える
4

あなたは正しい軌道に乗っていると思います。ただし、 Container クラスについては完全にはわかりません。ビジネス主導でそのインターフェースが必要でない限り、私は通常、これらのオブジェクトに「new」を使用するというより単純なソリューションに固執します。(この意味で「きちんとした」ことをビジネス要件とは考えていません)

しかし、「顧客であること」と「顧客を表示すること」を分離することは素晴らしいことです。それに固執してください。それはSOLID原則の素晴らしい解釈です。

個人的には、この種のコードであらゆる種類の静的メソッドの使用を完全に停止し、適切なサービス オブジェクトをすべて適切な場所と時間に取得するために DI に依存しています。SOLID の原則についてさらに詳しく説明し始めると、さらに多くのクラスを作成していることに気付くでしょう。一貫性を保つために、これらの命名規則に取り組むようにしてください。

于 2009-03-18T17:28:45.987 に答える
1

この「単一責任の原則」については聞いたことがありませんが、CustomerPrinter クラスと CustomerSaver クラスを使用して行っていることは、単純にクラスを構造体に変換し、オブジェクト指向を解除しているように見えます。すべての。

たとえば、これは、顧客のタイプが異なれば、別の方法で印刷する必要がある場合、CustomerPrinter クラスで異なるケースが必要になることを意味します。しかし、私が理解しているように、OO 組織と継承ツリーなどを使用するポイントの 1 つは、すべてを印刷する方法を知っているこの CustomerPrinter の必要性をなくすことです。つまり、顧客は自分自身を印刷する方法を知っています。

いずれにせよ、これらのパラダイムに厳密に従うことは信じていません。たとえば、あなたの場合、インターフェイスと抽象クラスの違いが何であるかわかりません。しかし、繰り返しになりますが、私は C# プログラマーではなく C++ プログラマーです...

于 2009-03-18T17:22:23.197 に答える
1

いくつかのメモ:

  • 一般的に言えば、SRP はすべて適切であり、データからの表示フォーマットの分離も同様です。
  • 表示などを考慮すると、むしろサービスの観点から考えたいと思います。つまり、PersonDisplayer は単一でステートレスであり、文字列 Display(IPerson) 関数を提供します。私見、表示を提供するためだけの特別なクラスラッパーは、何の利点もありません。
  • ただし、wpf にデータ バインディングを使用した場合は、Person が変更された場合に PropertyChanged を伝達する DisplayablePerson クラスが存在する可能性があります。DisplayablePerson オブジェクトを ObservableCollection に配置し、リスト コントロールの ItemsSource として提供します。
  • インスタンスをインスタンス化して構成するためだけにコンテナが必要ですか?それから試してください Customer customer1 = new Customer{FirstName= "Jim", LastName= "Smith"};

  • 補足として、私は object.Method < SomeType>(...) 呼び出しを数回試しました。しかし、しばらくすると、私はいつもそのトラブルに遭遇し、最終的に object.Method(Type someTypeType, ...) になりました

于 2009-03-18T17:44:14.717 に答える