Класс против структуры данных - PullRequest
24 голосов
/ 22 ноября 2010

В объектно-ориентированном программировании пользовательский класс (например, класс Person с данными Name, списком адресов и т. Д.) Содержит данные и может также включать объекты коллекции. Структура данных также используется для хранения данных. Итак, концептуально ли считается класс продвинутой структурой данных? И при проектировании эффективных систем (в объектно-ориентированном мире и больших системах) рассматриваются ли классы как сходные со структурами данных и алгоритмическим анализом, выполняемым для создания эффективных классов для большей эффективности (в таких компаниях, как Google, Facebook)?

Ответы [ 6 ]

23 голосов
/ 10 марта 2014

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

В соответствии с этим вы можете использоватьзанятия эффективно двумя разными способами.Это явление называется антисимметрией данных / объектов.В зависимости от ваших целей, вы должны решить, будут ли ваши классы следовать принципу открытый / закрытый или нет.
Если они следуют OCP, они будут полиморфными, а их экземпляры будут использоваться как объекты,Таким образом, они будут скрывать данные и реализацию общего интерфейса, и будет легко добавить новый тип, который также реализует этот интерфейс.Большинство шаблонов проектирования соответствуют OCP, например MVC, IoC, каждая оболочка, адаптер и т. Д. *
Если они не следуют OCP, они не будут полиморфными, их экземпляры будут использоваться в качестве данныхструктур.Таким образом, они будут предоставлять данные, и этими данными будут манипулировать другие классы.Это типичный подход и для процедурного программирования.Есть несколько примеров, в которых не используется OCP, например DTO, исключения, конфигурационные объекты, шаблон посетителя и т. Д.

Типичный шаблон, когда вы должны подумать о выполнении OCP и переместитькод для более низкого уровня абстракции:

class Manipulator {
    doSomething(Object dataStructure){
        if (dataStructure instanceof MyType1){
            // doSomething implementation 1
        }
        else if (dataStructure instanceof MyType2)
        {
            // doSomething implementation 2
        }
        // ...
    },
    domSomethingElse(Object dataStructure){
        if (dataStructure instanceof MyType1){
            // domSomethingElse implementation 1
        }
        else if (dataStructure instanceof MyType2)
        {
            // domSomethingElse implementation 2
        }
        // ...
    }
}

class MyType1 {}
class MyType2 {}
//if you want to add a new type, every method of the Manipulator will change

исправлено: перемещение реализации на более низкий уровень абстракции и выполнение OCP

interface MyType {
    doSomething();
    domSomethingElse();
}

class MyType1 implements MyType {
    doSomething(){
        // doSomething implementation 1
    },
    domSomethingElse(){
        // domSomethingElse implementation 1
    }
}

class MyType2 implements MyType {
    doSomething(){
        // doSomething implementation 2
    },
    domSomethingElse(){
        // domSomethingElse implementation 2
    }
}

// the recently added new type
class MyType3 implements MyType {
    doSomething(){
        // doSomething implementation 3
    },
    domSomethingElse(){
        // domSomethingElse implementation 3
    }
}

Типичный шаблон, когда вы должны подумать о нарушении OCP и переместить кодна более высокий уровень абстракции:

interface MyType {
    doSomething();
    domSomethingElse();

    //if you want to add a new method here, every class which implements this interface, will be modified
}

class MyType1 implements MyType {
    doSomething(){
        // doSomething implementation 1
    },
    domSomethingElse(){
        // domSomethingElse implementation 1
    }
}

class MyType2 implements MyType {
    doSomething(){
        // doSomething implementation 2
    },
    domSomethingElse(){
        // domSomethingElse implementation 2
    }
}

или

interface MyType {
    doSomething();
    domSomethingElse();
}

class MyType1 implements MyType {
    doSomething(){
        // doSomething implementation 1
    },
    domSomethingElse(){
        // domSomethingElse implementation 1
    }
}

class MyType2 implements MyType {
    doSomething(){
        // doSomething implementation 2
    },
    domSomethingElse(){
        // domSomethingElse implementation 2
    }
}

//adding a new type by which one or more of the methods are meaningless
class MyType3 implements MyType {
    doSomething(){
        throw new Exception("Not implemented, because it does not make any sense.");
    },
    domSomethingElse(){
        // domSomethingElse implementation 3
    }
}

Исправлено: перемещение реализации на более высокий уровень абстракции и нарушение OCP

class Manipulator {
    doSomething(Object dataStructure){
        if (dataStructure instanceof MyType1){
            // doSomething implementation 1
        }
        else if (dataStructure instanceof MyType2)
        {
            // doSomething implementation 2
        }
        // ...
    },
    domSomethingElse(Object dataStructure){
        if (dataStructure instanceof MyType1){
            // domSomethingElse implementation 1
        }
        else if (dataStructure instanceof MyType2)
        {
            // domSomethingElse implementation 2
        }
        // ...
    },
    // the recently added new method
    doAnotherThing(Object dataStructure){
        if (dataStructure instanceof MyType1){
            // doAnotherThing implementation 1
        }
        else if (dataStructure instanceof MyType2)
        {
            // doAnotherThing implementation 2
        }
        // ...
    }
}

class MyType1 {}
class MyType2 {}

или разделениеклассы в подклассы.

Люди обычно следуют OCP по количеству методов один или два, потому что повторять одни и те же операторы if-else недостаточно СУХОЙ.

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

7 голосов
/ 22 ноября 2010

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

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

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

7 голосов
/ 22 ноября 2010

Я бы сказал, что концептуально класс это НЕ структура данных, класс хорошо представляет, класс объектов и объекты абстрактны (в английском значении слова, а не C ++ или C # значение слова).

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

4 голосов
/ 22 ноября 2010

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

Взять, к примеру, связанный список. Вы можете реализовать структуру данных Linked List, используя класс, и в некоторых языках это самый чистый и очевидный способ сделать это. Это не единственный способ реализовать связанный список, но он может быть лучшим в зависимости от языка.

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

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

Классы часто поддаются использованию для реализации структур данных, но было бы неправильно говорить, что класс == структура данных.

1 голос
/ 22 ноября 2010

Классы описывают модель / концепцию / тип и определяют возможное поведение и возможные состояния этого (в вашем примере Person может иметь имя, адрес и т. Д.)

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

Вы можете иметькласс, представляющий структуру данных, например std::vector в C ++ или java.util.ArrayList в Java.

0 голосов
/ 04 марта 2017

Проще говоря, класс можно рассматривать как синтаксический инструмент, предоставляемый данным языком программирования, например Java, который объединяет данные и методы вместе для использования при реализации концепций или объектов в программе илиapplication.

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

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

Таким образом, оба различны в этом смысле.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...