2012-04-19 61 views
0

我知道在接口和基类中有很多贴子,但我很难得到正确的设计模式理解。了解接口和基类的使用

如果我要编写一个报告类,我的初始阶段应该是创建一个包含所有报告将实现的核心属性,方法等的接口。

例如:

Public Interface IReportSales 

Property Sales() As List(Of Sales) 
Property ItemTotalSales() As Decimal 

End Interface 

Public Interface IReportProducts 

Property Productss() As List(Of Inventory) 
Property ProductsTotal() As Decimal 

End Interface 

那么,我想我会一个类来实现的接口:

Public Class MyReport 
Implements IReportSales 


Public Property Sales() As System.Collections.Generic.List(Of Decimal) Implements IReportItem.Sales 
    Get 
     Return Sales 
    End Get 
    Set(ByVal value As System.Collections.Generic.List(Of Decimal)) 
     Items = value 
    End Set 
End Property 

Public Function ItemTotalSales() As Decimal Implements IReport.ItemTotalSales 
    Dim total As Decimal = 0.0 
    For Each item In Me.Sales 
     total = total + item 
    Next 
End Function 

End Class 

我的想法是,它应该是一个接口,因为其他报告不得使用“项目“,这样我可以实现用于给定报表类的对象。

我会离开吗?我还应该创建一个基类吗?我没有创建基类的逻辑是,并非所有的报告类都可以使用“Items”,所以我不想将它们定义在不被使用的地方。

+0

你能解释在这里实现接口的原因吗?你不觉得,这是给内存不必要的。我可以做到没有界面。对? – Pankaj 2012-04-19 18:17:36

+0

你的问题对我有点困惑。你担心实施更多不使用“项目”的报告?尽管如此,你已经在界面中定义了它。就目前而言,任何想要实现'IReport'的类都必须提供'Items()'属性和'ItemTotalSales()'函数。 – Thomas 2012-04-19 18:17:37

+0

仅仅因为你实现了一个包含Items的接口并不意味着你需要使用它。 – Xaisoft 2012-04-19 18:24:39

回答

2

为了试图回答你的问题,抽象类被用来为相关类提供一个共同的祖先。 .Net API中的一个示例是TextWriter。这个类提供了一个共同的祖先所有各种类,其目的是以某种方式写文本。

接口更适合用作适用于不属于同一对象“家族”但具有类似功能的不同对象的适配器。在.Net API中的各种集合中可以看到一个很好的例子。

例如,ListDictionary类提供了管理对象集合的功能。他们不通过继承分享共同的祖先,这是没有道理的。为了让它们之间容易互操作,它们实现了一些相同的接口。

这两个类实现IEnumerable。这干净地允许您使用ListDictionary任一类型的对象作为任何需要IEnumerable的操作数。多么美妙!

因此,现在在您设计新软件的情况下,您想要考虑如何将它融入您的问题空间。如果您通过继承抽象类来为这些类提供一个共同的祖先,那么您必须确保从它继承的所有项都是真正的基本类型。 (例如,A StreamWriterTextWriter)。不恰当地使用类继承可能会使您的API在将来非常难以构建和修改。

假设您为您的报表制作抽象类ReportBase。它可能包含一些非常通用的方法,所有报告都必须具备。也许它只是指定了方法Run()

然后您只有一种类型的报告,因此您需要定义一个从ReportBase继承的具体Report类。一切都很好。然后,您发现需要添加更多类型的报告,例如XReportYReportZReport。它们并不重要,但它们的工作方式不同,并有不同的要求。所有的报告生成漂亮的HTML输出,每个人都很开心。

下周您的客户说他们想要XReportYReport也能够输出PDF文档。现在有很多方法可以解决这个问题,但显然在抽象类中添加OutputPdf方法是一个糟糕的主意,因为其中一些报告不应支持或不支持此行为!

现在,这是接口可能对您有用的地方。假设您定义了几个接口IHtmlReportIPdfReport。现在,应该支持这些不同输出类型的报表类可以实现这些接口。然后,您可以创建一个函数,如CreatePdfReports(IEnumerable<IPdfReport> reports),它可以接受所有实现IPdfReport的报告,并执行它们需要的任何操作,而不必关心适当的基本类型。

希望这会有所帮助,因为我不熟悉你正在尝试解决的问题,所以我在这里从臀部开枪。

+0

这很棒,谢谢@Thomas。这是完全意义上的,我只是很难实施这个理论。我很欣赏你的时间。 – TreK 2012-04-19 18:54:07

+0

如果您不熟悉问题空间以及您将要解决的问题,那么对于您来说,我最大的建议就是不要陷入过度设计具有复杂类和界面结构的解决方案。写下你需要的东西,随着你意识到它会变得有益,愿意重构未来。 – Thomas 2012-04-19 18:57:09

+0

@TravisK也不会因为遇到困难而感到不快。好的设计难以置信,几乎(或可能从字面上)不可能第一次正确地获得。 – Thomas 2012-04-19 19:00:06

0

是的,如果你不知道有多少报告不打算使用物品,你可以去Abastract类。

另一个不错的想法如下:

您还可以创建接口和抽象类

定义销售在接口方面,创建两个抽象类,一个用于实现两个,另一个用于报告未实现销售报告。执行界面为

在第一个定义方法(实现销售),并且只实现第二个销售。

为这两个抽象类给出合适的名称,例如ReportWithItemsBase或ReportWithoutItemsBase。

通过这种方式,您还可以在派生Report类时自行解释指定的基类。

+0

感谢您的额外想法。 – TreK 2012-04-19 19:17:40