2010-11-22 16 views
20

En la programación orientada a objetos, una clase personalizada (como la clase Persona con datos de Nombre, lista de direcciones, etc.) contiene datos y puede incluir objetos de colección también. Una estructura de datos también se usa para almacenar datos. Entonces, ¿una clase se considera estructura de datos avanzada conceptualmente? Y en el diseño de sistemas eficientes (en el mundo orientado a objetos y sistemas grandes), ¿las clases se consideran similares a las estructuras de datos y el análisis algorítmico realizado para diseños de clases eficientes para una mayor eficiencia (en compañías como google, facebook)?Clase vs estructura de datos

Respuesta

4

Si una clase personalizada es una estructura de datos depende de a quién le pregunte. Por lo menos, la gente sí reconocería que es una estructura de datos definida por el usuario que es más específica del dominio y menos establecida que las estructuras de datos, tales como matrices, listas vinculadas o árboles binarios, por ejemplo. Para esta respuesta, los considero distintos.

Si bien es fácil aplicar el análisis de algoritmo Big O a las estructuras de datos, es un poco más complejo para las clases ya que envuelven muchas de estas estructuras, así como otras instancias de otras clases ... pero muchas operaciones en clase las instancias se pueden dividir en operaciones primitivas en estructuras de datos y se representan en términos de Big O. Como programador, puede esforzarse por hacer que sus clases sean más eficientes al evitar la copia innecesaria de miembros y asegurarse de que las invocaciones de métodos no pasen por demasiadas capas.Y por supuesto, el uso de algoritmos de rendimiento en sus métodos es evidente, pero eso no es específico de OOP. Sin embargo, la funcionalidad, el diseño y la claridad no deben sacrificarse a favor del rendimiento a menos que sea necesario. Y la optimización prematura es el diablo yada yada yada.

Estoy seguro de que algún académico, en alguna parte, ha intentado formular una métrica para cuantificar el rendimiento de clase o incluso un cálculo para las clases y sus operaciones, pero aún no lo he encontrado. Sin embargo, existe una investigación de QA como this que mide las dependencias entre clases en un proyecto ... uno podría argumentar que existe una correlación entre el número de dependencias y la estratificación de invocaciones de métodos (y por lo tanto, un rendimiento de clase inferior). Pero si alguien ha investigado esto, estoy seguro de que podría encontrar una métrica más relevante que no requiera inferencias amplias.

6

diría que conceptualmente una clase es NO una estructura de datos, una clase representa, así, una clase de objetos, y los objetos son abstractos (en el sentido Inglés de la palabra, no el C++ o C# significado de la palabra) entidades.

Diría que las clases y los objetos son como la teoría detrás de la práctica, y la práctica es la implementación de objetos utilizando métodos y datos. Los datos pueden ser simples o complejos (la llamada estructura de datos avanzada).

1

clases describen un modelo/concepto/tipo y define el comportamiento posible y posibles estados de que (en el ejemplo, un Person puede tener un nombre, dirección, etc.

Una estructura de datos es un tipo que puede se utilizará para organizar y agrupar ... datos de alguna manera. Por ejemplo, los vectores y las listas vinculadas son estructuras de datos que pueden usarse para almacenar datos de manera ordenada.

Puede tener una clase que represente datos estructura, como std::vector en C++, o java.util.ArrayList en Java.

3

A la clase es simplemente una colección de datos y métodos que pueden actuar sobre esa información. Puede usar una clase para implementar una estructura de datos, pero son cosas diferentes.

Tome la lista vinculada por ejemplo. Puede implementar una estructura de datos de Lista Vinculada usando una clase, y en algunos idiomas esta es la forma más clara y más obvia de hacerlo. No es la única forma de implementar una lista vinculada, pero podría ser la mejor según el idioma.

Sin embargo, una lista vinculada no tiene nada que ver con ser una clase. Una Lista Vinculada es, en cambio, una forma de representar los datos como nodos separados donde cada nodo está vinculado al siguiente de alguna manera.

Una estructura de datos es una forma conceptual de modelado de datos, cada estructura de datos diferente tiene diferentes propiedades y casos de uso. Una clase es una forma sintáctica que ofrecen algunos idiomas para agrupar datos y métodos.

Las clases a menudo se prestan a ser utilizadas para implementar estructuras de datos, pero sería incorrecto decir que una clase == una estructura de datos.

+0

¿Puede cualquier clase con campos no estáticos implementar una estructura de datos? ¿Una clase que contiene solo el campo foo se verá como una estructura de datos extremadamente simple? – Kelmikra

19

Le recomiendo que lea Clean Code capítulo 6: objetos y estructuras de datos. Todo el capítulo trata sobre esto ... Puede leer un resumen si no desea comprar el libro, se puede encontrar here.

De acuerdo con eso, puede usar clases de manera eficiente de dos maneras diferentes. Este fenómeno se llama antisimetría de datos/objetos. Dependiendo de tus objetivos, debes decidir si tus clases seguirán el open/closed principle o no.
Si siguen el OCP, serán polimorfos y sus instancias se usarán como objetos. Por lo tanto, ocultarán los datos y la implementación de una interfaz común, y será fácil agregar un nuevo tipo que implemente esa interfaz también. La mayoría de los patrones de diseño cumplen con el OCP, por ejemplo, MVC, IoC, cada contenedor, adaptador, etc.
Si no siguen el OCP, no serán polimorfos, sus instancias se usarán como estructuras de datos . Entonces expondrán los datos y esa información será manipulada por otras clases. Este es un enfoque típico de la programación de procedimientos también. Hay varios ejemplos que no utilizan OCP, por ejemplo, dtos excepciones, los objetos de configuración, etc ... visitor pattern

Patrón típico cuando se debe pensar en el cumplimiento de OCP y mover el código a un nivel de abstracción más baja:

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 

solución: la aplicación se mueve a un nivel de abstracción más bajo y cumplir con 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 
    } 
} 

patrón típico cuando se debe pensar que viola OCP y mover el código a un mayor nivel de abstracción:

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 
    } 
} 

o

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 
    } 
} 

solución: mover la aplicación a un nivel de abstracción más alto y violar 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 {} 

o dividir las clases en subclases.

La gente generalmente sigue OCP sobre el método count uno o dos porque repetir las mismas declaraciones if-else no es lo suficientemente DRY.

No le recomiendo que use clases mixtas que cumplen parcialmente, violan parcialmente el OCP, porque entonces el código será muy difícil de mantener. Debe decidir por cada situación qué enfoque sigue. Esta suele ser una decisión fácil, pero si comete un error, aún puede refactorizar su código más tarde ...

+0

No sé si creó o copió este ejemplo, pero es la primera vez que veo la opción presentada así y me pareció muy útil. Gracias. – Matt

+0

@Matt Este es mi ejemplo, sin embargo, hay un ejemplo similar en el Código de limpieza. Si recuerdo bien, es con diferentes formas. Todavía no estoy seguro sobre los principios SÓLIDOS, siempre me olvido cuál es cuál. : D SRP y DIP son fáciles, pero los demás ... – inf3rno

+0

Buenos ejemplos, gracias. –

0

En pocas palabras, una clase se puede ver como una herramienta sintáctica proporcionada por un lenguaje de programación dado, Java, que combina datos y métodos para su uso en la implementación de conceptos u objetos en un programa o aplicación.

Con una clase puede implementar un componente de software que es una representación de una idea u objeto en el mundo real. Para ello, debe capturar las propiedades del objeto como variables miembro y su comportamiento u operaciones como los métodos de la clase.

Las estructuras de datos por el contrario son básicamente modelos de manejo de datos (Array, Linked List, Binary Search Tree). Una clase se usa a menudo para implementar estructuras de datos debido a su forma única de capturar tanto el estado como el comportamiento de estas estructuras.

Los dos son por lo tanto distintos en este sentido.