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

Itemsを含むインターフェイスを実装しているだけで、それを使用する必要はありません。 – Xaisoft

答えて

2

質問に答えるために、抽象クラスを使用して関連するクラスの共通の祖先を提供します。 .Net APIのこの例はTextWriterです。このクラスは、テキストを何らかの形で書くことを目的とする、すべての共通の祖先を提供します。

インターフェイスはオブジェクトの同じ「ファミリ」に属していないが、同様の機能を持つさまざまなオブジェクトのアダプタとして機能するためにより適切に使用されます。これの良い例は、.Net APIのさまざまなコレクションで見ることができます。

たとえば、ListおよびDictionaryクラスを使用すると、オブジェクトのコレクションを管理できます。彼らは継承によって共通の祖先を共有しませんが、これは意味をなさないでしょう。しかし、それらの間の簡単なinteropを可能にするために、彼らはいくつかの同じインターフェイスを実装します。

どちらのクラスもIEnumerableを実装しています。これにより、IEnumerableが必要なオブジェクトのオペランドとして、ListまたはDictionaryのいずれかのオブジェクトを使用することができます。なんて素敵なの!

これで、新しいソフトウェアを設計する際に、これがあなたの問題空間にどのように適合するか考えたいと思っています。これらのクラスに抽象クラスの継承を介して共通の祖先を与える場合は、それを継承するすべてのアイテムが本当に基本型であることを確認する必要があります。 (例えば、StreamWriterは、TextWriterである)。クラス継承を不適切に使用すると、APIを将来構築および変更することが非常に困難になります。

あなたのレポジトリに抽象クラスReportBaseを作成したとします。すべてのレポートに必要な非常に一般的なメソッドがいくつか含まれている可能性があります。おそらくそれは単にメソッドを指定するだけですRun()

あなたはReportBaseから継承する具体的なReportクラスを定義するために、1つのタイプのレポートを作成します。すべてが素晴らしいです。次に、いくつかのタイプのレポートを追加する必要があることがわかります。例えば、XReportYReport、およびZReportです。彼らが何であるかは本当に問題ではありませんが、彼らは異なった働きをし、異なる要件を持っています。すべてのレポートはかなりのHTML出力を生成し、誰もが満足しています。

次の週、あなたのクライアントは、彼らがXReportYReportは同様に、出力PDF文書にできるようにしたいと言います。これを解決する方法はたくさんありますが、明示的に抽象クラスにOutputPdfメソッドを追加するのは難しいでしょう。これらのレポートの中にはこの動作をサポートしてはいけないか、サポートできないものがあります。

インターフェースはあなたに役立つ可能性が今どこにこれがあります。いくつかのインターフェイスを定義するとしましょう。IHtmlReportIPdfReportこれらのさまざまな出力タイプをサポートするはずのレポートクラスでは、これらのインターフェイスを実装できます。これにより、CreatePdfReports(IEnumerable<IPdfReport> reports)などの関数を作成して、IPdfReportを実装するすべてのレポートを作成し、適切な基本タイプのことを気にせずに、それらが必要な処理を実行できるようにします。

うまくいけば、これは、私はあなたが解決しようとしている問題に精通していないんだと、私は一種のここに腰から撮影した、ことができます。

+0

これはすばらしかった、ありがとう@トーマス。それは完全な意味を持っています。私は理論を実装するのが難しいだけです。私はあなたが時間だと感謝します。 – TreK

+0

問題空間と解決しなければならない問題にまだ精通していない場合は、複雑なクラスとインターフェイス構造を持つソリューションのオーバーエンジニアリングを試みることで、私の最大の示唆は避けてください。あなたが必要としていることを書いて、それが有益になることを実感しながら、リファクタリングを進めていきます。 – Thomas

+0

@TravisKも難しさを感じていません。良いデザインは信じられないほど難しく、ほとんど(あるいはおそらく文字通り)最初に正しいことができません。 – Thomas

0

あなたがアイテムを使用するつもりはありませんどのように多くの報告がわからない場合は、[はい、あなたはAbastractクラスのために行くことができます。

もう一つの良い考えは次のとおりです。

をあなたはまた、2つの抽象クラス、報告書は販売を実施していないため、両方と別のものを実装するレポートのための1つを作成し、インターフェイスでの販売を定義

インターフェースと抽象クラスの両方を作成することができます。両方

ためのインタフェースを実装する最初の(販売を実現する)の両方の方法を定義し、第二のみでの販売を実施します。

両方の抽象クラスに適切な名前を付けます。 ReportWithItemsBaseまたはReportWithoutItemsBaseです。

あなたも、同様のレポートクラスを派生で名前の基底クラスを説明する自己を実現することができますこの方法。

+0

追加のお礼ありがとうございます。 – TreK

関連する問題