Расширение списка‹T› и нарушение принципа открытости/закрытости

Я только что создал следующий метод в одном из моих классов

public static bool Assimilate(this List<Card> first, List<Card> second)
{
    // Trivial
    if (first.Count == 0 || second.Count == 0)
    {
        return false;
    }

    // Sort the lists, so I can do a binarySearch
    first.Sort();
    second.Sort();

    // Copia only the new elements
    int index;
    for (int i = 0; i < second.Count; i++)
    {
        index = first.BinarySearch(second[i]);
        if (index < 0)
        {
            first.Insert(~index, second[i]);
        }
    }

    // Edit
    second = null;

    return true;
}

И мой друг, просматривая мой код, сказал, что мне не следует создавать методы, которые «расширяют класс List», так как это нарушает принцип открытости/закрытости. Если я хочу расширить список классов, я должен создать новый класс, который наследуется от списка, и реализовать мой метод «слияния» в этом новом классе. Он прав? Расширение класса List нарушает принцип Open/Closed?


person Trauer    schedule 25.04.2014    source источник
comment
Я никогда не слышал термина «принцип открытости/закрытости», но из определения Википедии я не вижу, как это нарушает его.   -  person Cory Nelson    schedule 25.04.2014
comment
Изменение поведения класса было бы, но я не вижу этого здесь. Что мне не понравилось бы, так это то, что он изменяет входные списки (сортирует их), особенно второй список, как побочный эффект.   -  person Ralf    schedule 25.04.2014
comment
Вы должны серьезно спросить своего друга, знает ли он принцип Open/Closed.   -  person Sriram Sakthivel    schedule 25.04.2014
comment
Итак, с моим кодом все в порядке?   -  person Trauer    schedule 25.04.2014
comment
Ральф указал на одну потенциальную проблему с вашим кодом, но она не связана с методом расширения и подклассом. Есть ли необходимость сортировать второй список? Я не вижу, чтобы это служило какой-то реальной цели здесь.   -  person JLRishe    schedule 25.04.2014
comment
Сортировка ускорит поиск уникальных элементов. Плюс я не буду использовать второй после вызова этого метода.   -  person Trauer    schedule 25.04.2014
comment
Как сортировка second ускорит поиск? Вы перебираете его по одному элементу за раз. Сортировка second ничего не улучшает. Даже если прямо сейчас вы не используете его после вызова метода, вы все равно должны думать о последствиях своего дизайна и не иметь ненужных побочных эффектов (в конце концов, хороший дизайн не совсем то, что это вопрос о чем?).   -  person JLRishe    schedule 25.04.2014


Ответы (3)


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

Вы можете расширять объект по-разному в разных языках, наследование — это только один из способов; c# предоставляет вам возможность добавлять методы расширения к существующему классу.

Помните: «открыть для расширения — закрыть для модификации»

person Jaime    schedule 25.04.2014
comment
Я сказал это своему другу. Он сказал, что расширения должны быть сделаны через наследование ._. - person Trauer; 25.04.2014
comment
Почему? Есть ситуации, которые нельзя решить с помощью наследования, но которые можно решить с помощью методов расширения. Например, ваш пример теперь можно использовать со всем, что является List‹Card› (кстати, вы можете получить IList‹Card›), если бы вы реализовали это с наследованием, вам пришлось бы изменить класс списков, с которыми вы хотите использовать эту функцию. - person Jaime; 25.04.2014
comment
@Trauer Спросите своего друга, как он добавит расширение к классу String; например метод ToPascalCase. ? и давайте посмотрим, как он стоит на месте с нелепым утверждением что расширения должны быть сделаны через наследование! - person Sriram Sakthivel; 25.04.2014

Если использование метода расширения, а не подкласса, нарушает принцип открытости/закрытости, то по этой логике все методы расширения будут нарушать его, но это функция, которая была намеренно добавлена ​​в C# и широко используется в самой среде .NET, чтобы много пользы. (Без методов расширения у нас не было бы LINQ, и это было бы настоящим позором.)

Метод расширения не изменяет сам класс (с точки зрения модификации его кода) или какой-либо из его существующих функций, поэтому он не нарушает принцип открытости/закрытости.

person JLRishe    schedule 25.04.2014

Принцип открытия/закрытия — это принцип, а не предписание того, как этот принцип должен выглядеть на конкретном языке.

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

В большинстве языков наследование — единственный способ сделать такое расширение, поэтому принцип открытости/закрытости требует использования наследования. C# предоставляет вам два метода расширения: методы наследования и методы расширения. Нет ничего плохого в том, чтобы использовать их обоих.

person Josh Kelley    schedule 25.04.2014