2012-04-19 2 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 

Моя мысль в том, что он должен быть интерфейс, потому что другие отчеты могут не использовать " Элементы ", таким образом я могу реализовать объекты, которые используются для данного класса отчета.

Я ушел? должен ли я еще создать базовый класс? Моя логика не создания базового класса заключалась в том, что не все классы отчетов могут использовать «Элементы», поэтому я не хотел их определять, где они не используются.

+0

Можете ли вы объяснить причину реализации интерфейса здесь? Разве вы не думаете, что это дает память без необходимости. Я могу сделать это без интерфейса. Правильно? – Pankaj

+0

Ваш вопрос немного запутанный для меня. Вы беспокоитесь об использовании большего количества отчетов, которые не используют 'Items'? Тем не менее, у вас есть то, что определено в вашем интерфейсе. В настоящее время любой класс, который вы хотите реализовать «IReport», должен будет предоставить свойство 'Items()' и функцию ItemTotalSales(). – Thomas

+0

Просто потому, что вы реализуете интерфейс, содержащий элементы, не означает, что вам нужно его использовать. – Xaisoft

ответ

2

Чтобы ответить на ваш вопрос, абстрактные классы используются для обеспечения общего предка для связанных классов. Примером этого в API .Net является TextWriter. Этот класс обеспечивает общего предка всех различных классов, целью которых является, например, написать текст.

Интерфейсы более правильно используются в качестве адаптеров для разных объектов, которые не принадлежат к одному и тому же «семейству» объектов, но имеют схожие возможности. Хороший пример этого можно увидеть с помощью различных коллекций в API .Net.

Например, классы List и Dictionary предоставляют возможность управления коллекцией объектов. Они не имеют общего предка по наследству, это не имеет смысла. Чтобы обеспечить легкий переход между ними, они реализуют некоторые из тех же интерфейсов.

Оба класса реализуют IEnumerable. Это позволяет использовать объекты любого типа List или Dictionary в качестве операнда для всего, что требует IEnumerable. Как чудесно!

Итак, теперь в вашем случае при разработке нового программного обеспечения вы хотите подумать о том, как это будет вписываться в ваше проблемное пространство. Если вы дадите этим классам общий предок через наследование абстрактного класса, вы должны быть уверены, что все элементы, которые наследуются от него, действительно относятся к базовому типу. (A StreamWriter - это, например, TextWriter). Неправильное использование наследования классов может затруднить сбор и модификацию API в будущем.

Предположим, вы создали абстрактный класс, ReportBase, для ваших репотов. Он может содержать несколько очень общих методов, которые должны иметь все отчеты. Возможно, это просто указывает метод Run()

У вас есть только один тип отчета, который вы хотите создать, чтобы определить конкретный класс Report, который наследует от ReportBase. Все прекрасно. Затем вы узнаете, что вам нужно добавить еще несколько типов отчетов, XReport, YReport и ZReport для примера. Неважно, что это такое, но они работают по-разному и имеют разные требования. Все отчеты генерируют довольно HTML-выход, и все довольны.

На следующей неделе ваш клиент скажет, что они хотят XReport и YReport, чтобы иметь возможность выводить документы PDF. Теперь есть много способов решить эту проблему, но, очевидно, добавление метода OutputPdf к вашему абстрактному классу - это плохая идея, так как некоторые из этих отчетов не должны или не могут поддерживать это поведение!

Теперь это то, где интерфейсы могут быть вам полезны. Предположим, вы определили несколько интерфейсов IHtmlReport и IPdfReport. Теперь классы отчетов, которые должны поддерживать эти различные типы выходных данных, могут реализовать эти интерфейсы. Это позволит вам создать такую ​​функцию, как CreatePdfReports(IEnumerable<IPdfReport> reports), которая может принимать все отчеты, реализующие IPdfReport, и делать все, что от них требуется, не заботясь о том, какой тип базового типа.

Надеюсь, это помогает, я как бы стрелял из бедра здесь, так как я не знаком с проблемой, которую вы пытаетесь решить.

+0

Это было здорово, спасибо @Thomas. Я имею в виду, что мне сложно заниматься теорией. Я ценю, что вы время. – TreK

+0

Мое самое большое предложение для вас не должно увязнуть в попытке переустроить решение сложной структурой класса и интерфейса, если вы еще не знакомы с проблемным пространством и проблемами, которые вам придется решать. Напишите вещи по мере необходимости и будьте готовы к реорганизации в будущем, поскольку вы понимаете, что это станет полезным. – Thomas

+0

@TravisK также не чувствует себя плохо из-за трудностей. Хороший дизайн невероятно твердый и почти (или, возможно, буквально) невозможно получить в первый раз. – Thomas

0

Да, если вы не знаете, сколько отчетов не собираетесь использовать Элементы, вы можете перейти на класс Abastract.

Еще одна хорошая мысль следующим образом:

Вы также можете создать как интерфейс и абстрактный класс

Define продаж в интерфейсе, создать два абстрактных класса, один для отчетов, которые реализуют как и другой для отчета не осуществляет продаж. Внедрить интерфейс для

определить оба метода (реализовать продажи) в первом и только реализовать продажи во втором.

Дайте соответствующие имена обоим абстрактным классам, например. ReportWithItemsBase или ReportWithoutItemsBase.

Таким образом, вы также можете добиться самостоятельного объяснения именованных базовых классов при получении классов Report.

+0

Спасибо за дополнительную идею. – TreK