2017-06-23 68 views
6

Mam hierarchię TrendProviders, które są używane do dostarczania serii punktów danych (trendów) z różnych źródeł.C# polimorfizm + projektowanie leków generycznych - potrzebne porady

zacząłem z interfejsem Generic:

public interface ITrendProvider<T> where T: TrendResult 
{ 
    IEnumerable<T> GetTrends(); 
} 

TrendResult to klasa wynik z uzyskanych danych trendów i kod stanu pracy:

public class TrendResult 
{ 
    public TrendResult() 
    { 
     Points = new Dictionary<DateTimeOffset, decimal>(); 
    } 

    public TrendResultCode Code { get; set; } 
    public string Name { get; set; } 
    public string Identifier { get; set; } 
    public Dictionary<DateTimeOffset, decimal> Points { get; set; } 
} 

TrendResultCode jest następująca:

public enum TrendResultCode 
{ 
    OK, 
    DataParseError, 
    NoData, 
    UnknownError 
} 

Istnieją również dwa typy (do tej pory) z Bardziej szczegółowe interfejsy:

  • IFileTrendProvider - stosowane w celu otrzymania trendy żadnych plików.

  • IServerTrendProvider - służy do uzyskiwania trendów ze zdalnych serwerów, na przykład przy użyciu protokołu FTP.

IFileTrendProvider idzie tak:

public interface IFileTrendProvider : ITrendProvider<TrendResult> 
{ 
    IFileReader FileReader {get; set} 
    FileTrendDiscoveryPattern Pattern {get; set;} 
} 

IServerTrendProvider idzie tak:

public interface IServerTrendProvider : ITrendProvider<TrendResult> 
{ 
    IClient Client { get; set; } 
    Dictionary<string, string[]> RequestedServerTrendIDs { get; set; } 
} 

Konkretne klasy, która implementuje interfejsy są następujące:

Jednym FileTrend typu :

public class GenericFileTrendProvider : IFileTrendProvider<TrendResult> 
{ 
    public GenericFileTrendProvider() { } 

    public IFileReader FileReader {get; set} 
    public FileTrendDiscoveryPattern Pattern {get; set;} 

    public IEnumerable<TrendResult> GetTrends() 
    { 
     // Some code to obtain trends from file using FileReader 
    } 
} 

I jeden z rodzaju ServerTrend:

public class ServerATrendProvider : IServerTrendProvider<TrendResult> 
{ 
    public ServerATrendProvider() { } 

    public IClient Client { get; set; } 
    public Dictionary<string, string[]> RequestedServerTrendIDs { get; set;} 

    public IEnumerable<TrendResult> GetTrends() 
    { 
     // Some code to obtain trends from remote server using Client 
    } 
} 

Teraz, co chcę osiągnąć i gdzie ja potrzebuję twojej pomocy i porady:

IFileReader wprowadza własne kody błędów:

public enum FileReadResultCode 
{ 
    OK, 
    FileAlreadyOpen, 
    FileNotFound, 
    UnknownError 
} 

IClient wprowadza również kody błędów operacji specyficznych:

public enum ClientCode 
{ 
    OK, 
    InvalidCredentials, 
    ResourceNotFounds, 
    UnknownError 
} 

Ponieważ zarówno: IFileReader i IClient zwraca również własne kody błędów, jak mogłem intruduce je w obiekcie TrendResult zwróconej przez GetTrends() metody, tak że w końcu nie będzie też kilka informacji o „wewnętrznej” błąd, konkretny błąd nie tylko TrendResult?

musiałbym trochę elastyczne rozwiązanie - Myślałam o dziedziczenie z TrendResult i stworzyć FileTrendResult i ServerTrendResult dla każdego z konkretnymi dostawcami, a także zdefiniowania konkretnych wyliczeń błędach zarówno dlatego, że wrócą własny typ wyniku, ale może to zrobić w jakiś inny sposób?

+1

Świetne pytanie pitersmx. Zwykle nie dodajemy żadnych pozdrowień lub dziękujemy za wpis, aby upewnić się, że w poście jest jak najmniej hałasu. Zmieniłem twoje podziękowania za ciebie, tylko że wiesz. – Mafii

+1

Teraz potrzebuję wspaniałej odpowiedzi :) – pitersmx

+0

Czy konkretne wyniki odnoszą się do pojedynczego 'TrendResult' lub czy są one takie same dla wszystkich wyników trendów, które są odczytywane ze źródła (np. Pliku). Na przykład, czy 'GenericFileTrendProvider' odczytuje kilka plików naraz, aby niektóre z zwróconych' TrendResults' mogły mieć kod 'FileNotFound', podczas gdy inne miałyby' Ok' lub inny kod? – Markus

Odpowiedz

3

Zamiast predefiniowanego listę możliwych błędów w wyliczeń (TrendResultCode, FileReadResultCode, ClientCode ...) można zmienić klasę TrendResult do przechowywania listy wyjątków i pozbyć się wyliczeń:

public class TrendResult 
{ 
    // ...  
    // public TrendResultCode Code { get; set; } 
    public IEnumerable<Exception> Errors { get; set; } 
    // ... 
} 

ten sposób można przechowywać pełną informację o błędzie w tym śladu stosu i innych cennych informacji (lub kilku błędów, jeśli istnieje więcej niż jeden problem w jednym TrendResult). Nawet w przypadku nieoczekiwanych błędów możesz przechowywać dane zamiast mieć nieznany błąd, który trudno jest wyśledzić.

Jeśli TrendResult nie ma żadnych elementów w wyliczeniu, nie występują z nim żadne problemy. W przeciwnym razie możesz umieścić informacje w dzienniku.

Implementacja jest zgodna z Open/Closed principle, więc nie trzeba zmieniać implementacji, która obsługuje TrendResults, jeśli są nowe warunki, które prowadzą do błędu.

Dla wyjątków biznesowych, np. błędy parsowania, należy utworzyć określone typy wyjątków, aby później móc analizować te błędy na podstawie ich typów.

+0

Dzięki, spróbuję. Zaczynam bardzo lubić twoje rozwiązanie. Myślę, że to jest właściwa droga dla mnie. Jeszcze raz dzięki! – pitersmx

1

Odkąd IServerTrendProvider będzie odbierać TrendResults z innych komputerów, w ogólnym przypadku nie będzie można używać System.Exception.

W tych okolicznościach ludzie wracają do ciągów - które są zawsze obsługiwane niezależnie od systemu operacyjnego.

public class TrendResult 
{ 
    public string[] ErrorMessages; // Error messages - could be the stack trace 
    public int[] ErrorCodes;  // Os-specific error numbers 
} 

Rozważmy bezpieczeństwo podczas wysyłania fragmentów kodu źródłowego (na przykład nazwiska, stos ślady) komunikaty o błędach, ponieważ mogą one być wykorzystane przez hakerów.

Powiązane problemy