Пользовательская коллекция против общей коллекции для общедоступных методов

Каковы основные принципы разработки структуры для демонстрации пользовательской коллекции по сравнению с общей коллекцией? например

public class ImageCollection : Collection<Image>
{
     ...
}

public class Product
{
   public ImageCollection {get; set;}
}

В.С.

public class Product
{
   public Collection<Image> Images{get; set;}
}

Ответ 1

В общем, лучше всего выставить один из интерфейсов, например IEnumerable<T>, ICollection<T> или IList<T> вместо конкретного класса.

Это дает вам гораздо большую гибкость в плане изменения внутреннего API. IEnumerable<T>, в частности, позволяет вам позже модифицировать свои внутренние компоненты, чтобы обеспечить возможность потоковой передачи результатов, поэтому является наиболее гибким.

Если вы знаете ожидаемые шаблоны использования ваших "коллекций", вы должны выставить соответствующий API, который в будущем будет иметь наименьшие ограничения для вас. Если, например, вы знаете, что людям просто нужно повторять ваши результаты, выставляйте IEnumerable<T>, чтобы позже вы могли перейти в ЛЮБОЙ коллектив или даже переключиться непосредственно на возврат доходности.

Ответ 2

Если вы создаете открытый API, рассмотрите возможность использования пользовательской коллекции для следующих преимуществ.

  • Расширяемость - вы можете добавлять функции в свою коллекцию в будущем без изменения API.

  • Обратная совместимость - вы можете свободно изменять внутренности своего класса коллекции, не нарушая существующий код, который запрограммировали клиенты против коллекции.

  • Также легче сделать потенциально разрушающие изменения с меньшим воздействием. Возможно, позже вы решите, что не хотите, чтобы это был Collection<Image>, но другой тип коллекции - вы можете адаптировать свой класс ImageCollection к тем же методам, что и раньше, но наследовать от чего-то другого - и код клиента не будет вероятно, сломается.

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

В качестве примера, приведенного в моей главе, является API-интерфейс ArcGIS Server от ESRI - они используют собственные коллекции в своих API-интерфейсах. Мы также используем пользовательские коллекции в нашем API в основном по этим причинам.

Ответ 3

Я бы пошел на второй. Клиентский код должен знать тип изображения в любом случае.

Первый означает только больше кода.

Ответ 4

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

Кроме того, просто в сторону, вы должны действительно только разоблачить геттер для этой коллекции и инициализировать поле для чтения только с фактической коллекцией. Вероятно, вы хотите, чтобы люди добавляли/удаляли элементы в коллекцию, а не заменяли все:

class Product {
    private readonly Collection<Image> _images;
    public Product() { _images = new Collection<Image>(); }
    public Collection<Image> Images { get { return _images; } }
}

-Oisin

Ответ 5

Единственная причина когда-либо использовать Collection<T> - это если вы хотите подключиться к набору виртуальных методов, которые позволяют вам видеть все мутации в базовом списке. Это позволяет выполнять такие операции, как реагировать на удаление, осуществлять события и т.д.

Если вы не заинтересованы в просмотре или просмотре этих модификаций коллекции, тогда List<T> является более подходящим типом.

Ответ 6

Я предпочитаю иметь общедоступное универсальное свойство, чтобы сделать внутренности расширяемыми, но частное поле было бы обычным с фактической функциональностью.

Обычно это выглядит так:

public interface IProduct
{
     ICollection<Image> Images { get; }
}

public class Product : IProduct
{
   private class ImageCollection : Collection<Image>
   {
      // override InsertItem, RemoveItem, etc.
   }

   private readonly ImageCollection _images;
   public ICollection<Image> Images
   {
      get { return _images; }
   }
}

Я также часто делаю класс пользовательской коллекции вложенным в другой класс, что позволяет мне модифицировать некоторые частные члены родительского класса во время добавления/удаления.