2010-01-27 7 views
0

Я начинаю видеть значение интерфейсов vs. позволяет говорить абстрактным классом.Справка Создание интерфейса

В настоящее время я работаю над проектом PayPal Wrapper. Вероятно, мы также будем делать обложку Google Payments, BillMeLater и Amazon. Мне было предложено определить некоторые общие черты (методы, свойства и т. Д.), Которые мы могли бы использовать по всем направлениям, в большинстве проектов веб-службы SOAP Wsdl Wrapper для любых веб-сервисов, которые мы делаем.

Так как я кодирование моих оберток PayPal, я создал новый класс для хранения ошибок получили обратно от какого-либо ответа PayPal:

public class ApiError 
{ 

    #region Constructors 

    /// <summary> 
    /// Disallow default instantiation. 
    /// </summary> 
    private ApiError() 
    { 
    } 

    internal ApiError(ErrorType error) 
    { 
     if(error.ErrorCode != null) 
     { 
      this._errorCode = error.ErrorCode; 
     } 
    } 

    #endregion 

    #region member variables 

    private string _errorCode = string.Empty; 
    private string _erorMessage = string.Empty; 

    #endregion 

    #region Properties 

    public string ErrorCode 
    { 
     get { return _errorCode; } 
     set { _errorCode = value; } 
    } 

    public string ErrorMessage 
    { 
     get { return _errorMessage; } 
     set { _errorMessage = value; } 
    } 

    #endregion 

} 

Во всяком случае, я сказал, эй, эти ErrorMessage и ERRORCODE свойство, скорее всего, собирается быть в каждом стороннем API. Так почему бы не создать интерфейс в новом проекте под названием [MyCompany] .WebServices.Common и в этом интерфейсе добавить эти 2 свойства. Тогда любая оболочка класса, которую я создаю, которая имеет функциональность для создания запросов API-прокси, может реализовать этот интерфейс, и тогда я знаю, что любой из этих классов оболочек в любом из наших проектов веб-сервисов будет гарантированно иметь такие свойства в них, которые будут быть уничтожены и заполнены любыми ошибками, которые возвращаются из ответа API.

И если это так, то это здорово, потому что я могу начать создавать вспомогательные методы, которые мы можем использовать по всем направлениям, если я могу как-то взять общий объект ответа и заполнить массив ошибок и установить свойство.

В любом случае, моя проблема в том, что я новичок в интерфейсах litte. Таким образом, свойство массива ошибок сверху, например, имеет собственный тип.

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

Так что, если вы заглушите этот интерфейс, как бы я справился с этим?

namespace [MyCompany].WebServices.Common 
{ 
    interface IRequest 
    { 

     public ApiError Type { get; set; } //whoops, that's a custom type that this project does not know about (ApiError) 
    } 

} 

ответ

1

Каждая проблема в программном обеспечении может быть решена с помощью другого слоя без указания направления !!! Просто добавьте еще один интерфейс под названием IAPIError, который вы реализуете для каждого типа ошибки оплаты.

interface IRequest 
{ 
    public IApiError Type { get; set; } 
} 
+0

Я не понимаю. Итак, как IApiError знает о моем конкретном типе ApiError? – PositiveGuy

+0

Это наоборот. Конкретный класс ApiError реализует IApiError. Какой бы класс, который реализует IRequest, не знает, какие объекты APIError он должен возвращать и делает это. –

+0

А я вижу. Поэтому у меня будет класс ApiResponse в любом проекте, реализующем IRequest. Поскольку он реализовал IRequest, он также должен реализовать IApiError, и поэтому класс ApiResponse должен иметь любые свойства в IApiError? – PositiveGuy

0

Вы можете поместить ваши общие типы в отдельной общей сборки: [MyCompany] .WebServices.Shared

Редактировать
Давай думать об этом, у вас уже есть что. [MyCompany] .WebServices.Common должен быть таким же хорошим местом, как и для ваших общих типов. Просто переместите его туда. Или я не понимаю, что вы хотите сделать?

+0

, тогда в этом случае этот тип должен быть изменен на более общий базовый класс, чтобы я мог также расширить его, а затем в каждом проекте оболочки. Я думаю, – PositiveGuy

0

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

Я бы добавил еще одну абстракцию, указав ожидаемые ошибки (одна из которых является «неизвестной ошибкой» как обломок для неожиданных ошибок) как отдельный класс или даже как набор исключений. Затем, каждый провайдер возвращает или использует те, которые уже совместимы с вашим приложением и позволяют обрабатывать распространенные ошибки для всех провайдеров одинаково.

Поместите эти общие типы в отдельную сборку, которая представляет собой чистую «интерфейсную» сборку, используемую как провайдерами, так и фактический код, используя их.Поэтому вы сможете свободно связывать поставщиков, не добавляя ссылки на них в основное приложение (позволяя добавлять или изменять поставщиков без перекомпиляции приложения).

+0

Номера ошибок и типы сообщений могут обрабатываться Enums, что каждый проект оболочки реализует себя. Я могу гарантировать, что каждый API будет иметь номера ошибок. И каждый API будет иметь общее сообщение об ошибке. Таким образом, это 2 перечисления, которые интерфейс может также заставить. То, что вы говорите, относительно как это реализовано. Не совсем верно то, что вы здесь говорите ... потому что есть способы, которыми вы можете заставить это работать. – PositiveGuy

+0

Дело в том, что коды ошибок для «недопустимой карты», «услуги недоступны», «прерваны» или все, что там будет, будет отличаться для каждого провайдера, поэтому вам необходимо иметь общий набор ошибок, которые переводятся каждым поставщиком, и который будет * не * быть треском ошибки поставщика е. Перечисления, предоставляемые конкретным провайдером, не помогут вам здесь. – Lucero

+0

внутренний ApiError (ErrorType error) { if (error.ErrorCode! = Null) { this._errorCode = error.ErrorCode; } ErrorCode - это перечисление, определенное любым классом, реализующим этот интерфейс. Почему это имеет значение, все, что я делаю, возвращает его как свойство! – PositiveGuy

2

Вы должны учитывать, что ApiErrors будут зависеть от конкретной реализации веб-сервиса. Итак, как клиент, который использует только интерфейсы, будет использовать ApiErrors, если они специфичны для реализации?

Этого не может быть - потому что это будет означать, что оно связано с этой конкретной реализацией.

Вместо этого вам необходимо отвлечься от конкретных кодов ошибок API и определить свои собственные коды ошибок.

+0

+1 - точно, что я говорю, но другими словами. – Lucero

+0

Обильно, но вы можете использовать Enums для ErrorType и ErrorNumber и ErrorMessage. Интерфейс просто говорит, что вам нужно предоставить как минимум массив ошибок в качестве свойства. Теперь ErrorCode является alos требуемым свойством, и все API-интерфейсы будут иметь код ошибки, и это может быть перечисление, определенное в каждом классе, реализующем это свойство. – PositiveGuy

+0

ErrorCode - это перечисление внутри конкретного типа ApiError. Поэтому, если я могу абстрагировать тип ApiError в свойстве Interface, по крайней мере, у них также должен быть какой-то Enum, называемый ErrorCode. У каждого API будет, по крайней мере, код ошибки. – PositiveGuy

Смежные вопросы