我制作了以下代码示例,以了解如何使用泛型方法签名。
为了获得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; }
}
}
答案 0 :(得分:8)
我喜欢将Single Responsibility Principle视为separation of duties的实现。在我开始分割我的课程之前,我试着想一下每个班级应该负责什么。
您的课程非常简单,并且适用于具有已实现的Print()
和Save()
函数的抽象类。我倾向于将这种设计保留在你当前的设计之上。
但是,如果打印和保存是可能以不同方式执行的更复杂的任务,那么将保证专用的Printer
或Saver
类,因为此责任现在更加复杂。制作新课程的“复杂性”门槛非常主观,取决于具体情况,但最后,代码只是我们低级人类理解的抽象,所以要使它最直观。< / 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)
一些注意事项:
您需要什么容器,是否仅用于实例化和配置实例?请尝试然后客户customer1 =新客户{FirstName =“Jim”,LastName =“Smith”};
在旁注中,我尝试过object.Method&lt; SomeType&gt;(...)调用几次,因为它似乎是最快最简单的解决方案。但是,经过一段时间后,我总是遇到麻烦而最终遇到了object.Method(输入someTypeType,...)
答案 4 :(得分:0)
您可以查看IFormattable和IFormatProvider。
该框架具有支持的格式化类。