Custom Collection vs Generic Collection для открытых методов
Каковы основные принципы разработки структуры для демонстрации пользовательской коллекции по сравнению с общей коллекцией? например
public class ImageCollection : Collection<Image>
{
...
}
public class Product
{
public ImageCollection {get; set;}
}
В.С.
public class Product
{
public Collection<Image> Images{get; set;}
}
6 ответов
В общем, лучше выставить один из интерфейсов, например IEnumerable<T>
, ICollection<T>
или же IList<T>
вместо конкретного класса.
Это дает вам гораздо большую гибкость в плане изменения вашего внутреннего API. IEnumerable<T>
в частности, позволяет вам потенциально модифицировать ваши внутренние компоненты позже, чтобы обеспечить потоковую передачу результатов, поэтому является наиболее гибким.
Если вы знаете ожидаемые модели использования ваших "коллекций", вы должны предоставить соответствующий API, который обеспечит вам наименьшее количество ограничений в будущем. Если, например, вы знаете, что людям просто нужно повторять ваши результаты, выставьте IEnumerable<T>
, так что вы можете перейти на ЛЮБУЮ коллекцию позже, или даже переключиться на использование только прямого возврата.
Если вы создаете публичный API, рассмотрите возможность использования пользовательской коллекции для следующих преимуществ.
Расширяемость - вы можете добавлять функции в свою собственную коллекцию в будущем без изменения API.
Обратная совместимость - вы можете по своему усмотрению изменять внутренние компоненты вашего класса коллекции, не нарушая существующий код, который клиенты запрограммировали для коллекции.
Также легче вносить потенциально разрушительные изменения с меньшим воздействием. Возможно, позже вы решите, что не хотите, чтобы это было
Collection<Image>
, но другой тип коллекции - вы можете адаптировать свойImageCollection
класс должен иметь те же методы, что и раньше, но наследовать от чего-то другого - и клиентский код вряд ли сломается.
Если это только для внутреннего использования кода, решение не обязательно так важно, и вы можете решить, что "проще, тем лучше".
Примером из головы в голову служат ArcGIS Server API от ESRI - они используют собственные коллекции в своих API. Мы также используем пользовательские коллекции в наших API в основном по этим причинам.
Основная причина, по которой я могу придумать, заключается в том, что вам могут понадобиться некоторые методы, специфичные для коллекции изображений, которые работают с самой этой коллекцией. Тогда я бы использовал класс ImageCollection, чтобы содержать эти методы. Классическая инкапсуляция.
Кроме того, только в стороне, вы должны на самом деле только выставить геттер для этой коллекции и инициализировать поле только для чтения с фактической коллекцией. Вы, вероятно, хотите, чтобы люди добавляли / удаляли элементы в коллекции, а не заменяли всю вещь:
class Product {
private readonly Collection<Image> _images;
public Product() { _images = new Collection<Image>(); }
public Collection<Image> Images { get { return _images; } }
}
-Oisin
Я бы пошел на второй. Клиентский код должен знать тип изображения в любом случае.
Первый только означает больше кода.
Единственная причина когда-либо использовать Collection<T>
если вы хотите подключиться к набору виртуальных методов, который позволяет вам видеть все мутации в базовом списке. Это позволяет вам выполнять такие операции, как реакция на удаление, реализацию событий и т. Д.
Если вы не заинтересованы в ответе или просмотре этих модификаций коллекции, тогда List<T>
это более подходящий тип.
Я предпочитаю иметь открытое универсальное свойство, чтобы сделать внутреннее расширение расширяемым, но частное поле было бы пользовательским с реальной функциональностью.
Обычно это выглядит так:
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; }
}
}
Я также часто делаю собственный класс коллекции, вложенный в другой класс, что позволяет мне изменять некоторые закрытые члены родительского класса во время добавления / удаления.