这是单一责任原则的一个例子吗?

时间:2009-03-18 17:11:53

标签: c# design-patterns solid-principles

我制作了以下代码示例,以了解如何使用泛型方法签名。

为了获得Customer和Employee的 Display()方法,我实际上开始用 Person抽象类替换 IPerson接口

然后我停下来,记得一个播客,其中鲍勃叔叔告诉斯科特汉塞尔曼关于单一责任原则,其中你应该有很多小班,每个班做一件特定的事情,即客户class不应该有 Print() Save() 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; }
    }
}

5 个答案:

答案 0 :(得分:8)

我喜欢将Single Responsibility Principle视为separation of duties的实现。在我开始分割我的课程之前,我试着想一下每个班级应该负责什么。

您的课程非常简单,并且适用于具有已实现的Print()Save()函数的抽象类。我倾向于将这种设计保留在你当前的设计之上。

但是,如果打印和保存是可能以不同方式执行的更复杂的任务,那么将保证专用的PrinterSaver类,因为此责任现在更加复杂。制作新课程的“复杂性”门槛非常主观,取决于具体情况,但最后,代码只是我们低级人类理解的抽象,所以要使它最直观。< / p>

Container课程有点误导。它实际上并不包含任何东西。它实际上实现了Factory Method Pattern,并且可以从命名为工厂中受益。

此外,您的PersonDisplayer从未实例化,并且可以通过静态方法提供其所有功能,那么为什么不将其设为静态类呢?像utility classes这样的打印机或储蓄器是静态的并不罕见。除非您需要具有不同属性的打印机的单独实例,否则请将其保持静态。

答案 1 :(得分:4)

我认为你走在正确的轨道上。虽然我不完全确定Container类。我通常坚持使用对这些对象使用“new”的简单解决方案,除非你对该接口有一些业务驱动的需求。 (在这个意义上,我不认为“整洁”是一种商业要求)

但是,将“成为”客户责任与“展示客户”分开是很好的。坚持这一点,这是对SOLID原则的很好解释。

我个人已经完全停止在这种代码中使用任何类型的静态方法,我依靠DI在正确的地方获得所有正确的服务对象&amp;时间。一旦你开始进一步阐述SOLID原则,你会发现你正在制作更多的课程。尝试使用这些命名约定以保持一致。

答案 2 :(得分:1)

好吧,我之前从未听说过这个“单一责任原则”,但是我认为通过拥有这些CustomerPrinter类和CustomerSaver类所做的事情只是将类转换回结构,并且面向对象的一切。

例如,如果需要以不同方式打印,这意味着不同的客户类型在CustomerPrinter类中需要不同的情况。但正如我所理解的那样,OO组织的一个重点,以及使用继承树以及所有这些,是为了消除此CustomerPrinter的需要,以了解如何打印所有内容:客户知道如何打印自己。

在任何情况下,我都不相信严格遵循这些范式。例如,我不确定接口和抽象类之间的区别是什么。但是我再次成为C ++程序员而不是C#程序员......

答案 3 :(得分:1)

一些注意事项:

  • 一般来说,SRP一切都很好,显示格式与数据的分离也是如此。
  • 考虑显示等。我宁愿考虑服务,即PersonDisplayer是单一的,无状态的,并提供字符串显示(IPerson)功能。恕我直言,一个特殊的类包装器只是为了提供显示而不提供任何优势。
  • 但是,如果您对wpf使用了数据绑定,则可能有一个DisplayablePerson类,如果Person更改,它将传播PropertyChanged。您可以将DisplayablePerson对象放入ObservableCollection并将其作为某些列表控件的ItemsSource提供。
  • 您需要什么容器,是否仅用于实例化和配置实例?请尝试然后客户customer1 =新客户{FirstName =“Jim”,LastName =“Smith”};

  • 在旁注中,我尝试过object.Method&lt; SomeType&gt;(...)调用几次,因为它似乎是最快最简单的解决方案。但是,经过一段时间后,我总是遇到麻烦而最终遇到了object.Method(输入someTypeType,...)

答案 4 :(得分:0)

您可以查看IFormattableIFormatProvider

该框架具有支持的格式化类。