2014-07-12 11 views
5

Mam klasę, która przechowuje pewne szczegóły w dużej strukturze danych, akceptuje algorytm do wykonywania na niej pewnych obliczeń, ma metody sprawdzania danych wejściowych do struktury danych. Ale chciałbym zwrócić strukturę danych, aby można było przekształcić ją w różne formularze wyjściowe (ciąg/C# DataTable/niestandardowe wyjście pliku) przez model widoku.OO Design - Ujawnianie szczegółów implementacji za pomocą interfejsu

class MyProductsCollection { 
    private IDictionary<string, IDictionary<int, ISet<Period>>> products; 

    // ctors, verify input, add and run_algorithm methods 
} 

Wiem, że należy używać zasady projektowania "polegaj na interfejsie, a nie implementacji", dlatego chcę utworzyć interfejs dla klasy.

Jak mogę uniknąć pisania następującego interfejsu? Powód tego ujawnia szczegóły implementacji i wiąże wszelkie inne konkretne implementacje, aby zwrócić ten sam formularz.

interface IProductsCollection { 
    IDictionary<string, IDictionary<int, ISet<IPeriod>>> GetData(); 
    // other methods 
} 

Jak mogę łatwo iterować nad strukturą danych, aby utworzyć różne odmiany produktów bez demonstrowania tego w ten sposób?

EDIT:

Ponieważ klasa bierze w IFunc<IDictionary<string, IDictionary<int, ISet<IPeriod>>>> w konstruktorze iteracyjne nad struktury danych i wykonywania obliczeń, mogę dostarczyć go innym IFunc, które skonstruowania wyjście zamiast obliczeń rzędu. Jednak nie wiem, jak mogłem to zrobić poza konkretnym konstruktorem klasy.

+0

Użyj metody abstrakcyjnej i metod wirtualnych. Klasy abstrakcyjne to także * interfejsy *. – pasty

Odpowiedz

2

Struktura IDictionary<string,IDictionary<int,ISet<Period>>> jest bardzo podejrzana - kiedy widzisz słownik słowników, istnieje duża szansa, że ​​przegapiłeś okazję lub dwie, aby utworzyć klasę do enkapsulacji wewnętrznego słownika.

Bez znajomości dziedziny problemu, sugerowałbym zdefiniowanie interfejsu do enkapsulacji wewnętrznego słownika. To wygląda jak coś, co kojarzy numer telefonu do zestawu okresów, więc można zdefiniować interfejs tak:

interface IYearlyPeriods { 
    bool HasPeriodsForYear(int year); 
    ISet<Periond> GetPeriodsForYear(int year); 
} 

nie mam pojęcia, co jest w okresach, więc trzeba by wybrać nazwę domeny specyficznych dla interfejsu.

Ponadto można zawinąć kolejny poziom IDictionary też:

interface IProductDataSource { 
    IEnumerable<string> ProductNames { get; } 
    IYearlyPeriods GetProductData(string productName); 
} 

Teraz można zdefiniować interfejs tak:

interface IProductsCollection { 
    IProductDataSource GetDataSource(); 
    // other methods 
} 

Głównym pomysłem jest wykorzystanie interfejsów domen specyficznych w miejsce generycznych kolekcji, aby czytelnicy i realizatorzy twojego kodu mieli jakieś pojęcie o tym, co jest w środku, bez odwoływania się do dokumentacji.

Możesz pójść jeszcze dalej i zastąpić IDictionary złożoną strukturą, którą zachowujesz wewnętrznie za pomocą implementacji IDictionary z IProductPeriods. Jeśli chcesz zachować IYearlyPeriods, który narażasz na niezmienność użytkowników, ale chciałbyś móc samemu dokonać modyfikacji, możesz wykonać implementację zmienną i zachować ją w klasie implementacji.

+0

Struktura danych odwzorowuje nazwy produktów (ciągi) na niektóre dane roczne (drugi identyfikator). To z kolei odwzorowuje rok (int) na liczbę kropek (set). Same okresy są po prostu fikcyjną klasą o właściwościach: period number (int) i amount (double). – oskarm

0

Proponuję zachować prywatność i udostępnić prosty IDictionary w interfejsie.

W twoim przypadku może to być niestandardowy DTO, który ukrywa całą złośliwość IDictionary<int, ISet<IPeriod>> - która jest już dość skomplikowana i może (prawdopodobnie) łatwo ulec zmianie, ponieważ musisz wdrożyć nowe funkcje.

To może być coś takiego:

class ExposedPeriod 
{ 
     public int PeriodIdentifier { get; set; } 
     public IEnumerable<IPeriod> Periods { get; set; } 
} 

ExposedPeriod i PeriodIdentifier prawdopodobnie potrzebujemy lepszych nazw chociaż. Dobre nazwy można znaleźć w słowniku domeny.

Powiązane problemy