2016-04-14 11 views
4

Когда я занимаюсь разработкой, я обычно стараюсь следовать принципам SOLID. Обычно у вас есть интерфейс, который реализуется всеми затронутыми классами, а затем использовать интерфейс в качестве параметра при дальнейших вычислениях.Clean Code: SRP и Open/Closed при получении данных из веб-сервисов

Мой вопрос: как это можно достичь при вызове, например, веб-службы? Нижеприведенный ниже код не очень тощий и НЕ действительно соответствует шаблону единой ответственности и принципу «открытый/закрытый».

Как бы вы изменить дизайн следующий код, чтобы следовать SRP и O/C:.

public class Fetch 
    { 
     public void Run() 
     { 
      var url = "https://api.nasa.gov/planetary/apod?api_key=NNKOjkoul8n1CH18TWA9gwngW1s1SmjESPjNoUFo"; 
      var client = new HttpClient(); 
      var response = client.GetAsync(url).Result; 
      var data = response.Content.ReadAsStringAsync().Result; 
      var parsedData = JsonConvert.DeserializeObject<Nasa>(data); 

      if(parsedData.media_type.Equals("image")) 
      { 
       CreateImage(parsedData); 
      } 

      if (parsedData.media_type.Equals("video")) 
      { 
       CreateVideo(parsedData); 
      } 

      if (parsedData.media_type.Equals("text")) 
      { 
       CreateText(parsedData); 
      } 
     } 
    } 

    public class Nasa 
    { 
     public string copyright { get; set; } 
     public string date { get; set; } 
     public string explanation { get; set; } 
     public string hdurl { get; set; } 
     public string media_type { get; set; } 
     public string service_version { get; set; } 
     public string title { get; set; } 
     public string url { get; set; } 
    } 

(Ключ Api взят из примера сайта НАСА, так что не беспокойтесь о подвергая его Асинхронный часть используя .Result только для этого примера)

+2

Это было бы лучше на codereview –

+0

Это не код, который мы используем. Это всего лишь общая проблема/дискуссия вокруг «Чистого кода» и веб-служб. – Hypnobrew

+2

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

ответ

3

Не зная о ваших потребностях или о том, как работают CreateVideo(item) и CreateImage(item), вы можете использовать это как отправную точку.

Обратите внимание: если вы используете контейнер зависимостей (например, Simple Injector, имейте это в виду), то большая часть зависимостей в следующем может быть предоставлена ​​контейнером.

public class Nasa 
{ 
    public string copyright { get; set; } 
    public string date { get; set; } 
    public string explanation { get; set; } 
    public string hdurl { get; set; } 
    public string media_type { get; set; } 
    public string service_version { get; set; } 
    public string title { get; set; } 
    public string url { get; set; } 
} 

public interface ITransformFetch<in T> 
{ 
    void Transform(T data); 
} 

public interface IFetch<T> 
{ 
    T Fetch(); 
} 

public class NasaFetcher : IFetch<Nasa> 
{ 
    private const string NasaUrl = "https://api.nasa.gov/planetary/apod?api_key=NNKOjkoul8n1CH18TWA9gwngW1s1SmjESPjNoUFo"; 

    private readonly IHttpClientWrapper _client; 

    public NasaFetcher(IHttpClientWrapper client) 
    { 
     _clientFactory = client; 
    } 

    public Nasa Fetch() 
    { 
     var response = _client.GetAsync(NasaUrl).Result; 
     var data = response.Content.ReadAsStringAsync().Result; 
     return JsonConvert.DeserializeObject<Nasa>(data); 
    } 
} 

public class NasaFetchImageTransformer : ITransformFetch<Nasa> 
{ 
    public void Transform(Nasa data) 
    { 
     // transform data 
    } 
} 

public class NasaFetchVideoTransformer : ITransformFetch<Nasa> 
{ 
    public void Transform(Nasa data) 
    { 
     // transform data 
    } 
} 

public class NasaFetcherTransformerDecorator : IFetch<Nasa> 
{ 
    private readonly IFetch<Nasa> _fetcher; 

    public NasaFetcherTransformerDecorator(IFetch<Nasa> fetcher) 
    { 
     _fetcher = fetcher; 
    } 

    public Nasa Fetch() 
    { 
     var result = _fetcher.Fetch(); 
     if (result != null) 
     { 
      switch (result.media_type) 
      { 
       case "image": 
        var nasaFetchImageTransformer = new NasaFetchImageTransformer(); 
        nasaFetchImageTransformer.Transform(result); 
        break; 

       case "video": 
        var nasaFetchVideoTransformer = new NasaFetchVideoTransformer(); 
        nasaFetchVideoTransformer.Transform(result); 
        break; 
      } 
     } 

     return result; 
    } 
} 

public class Test 
{ 
    public void TestNasaFetcher() 
    { 
     var data = new NasaFetcherTransformerDecorator(new NasaFetcher(new HttpClientWrapper())); 
     var nasa = data.Fetch(); 
    } 
} 
+0

Хм, поэтому, если API добавит новый тип носителя, мы добавим новый Transformen, а затем добавим новый 'case 'в коммутаторе. Разве это не нарушает принцип «открытого/закрытого»? – Hypnobrew

+0

Вы также можете просто создавать декораторы для каждого трансформатора и обертывать объект - скорее всего, используя контейнер IoC. – janhartmann