repositorio pattern patrones patron net mvc explicacion example diseño abstracto android design-patterns android-mvp

android - pattern - ¿El proveedor de contenidos es una implementación del patrón de repositorio?



repository pattern c# mvc (8)

El problema con el uso de ContentProviders como Repository es que agrega una dependencia en su modelo a Android Framework. El uso de los patrones de repositorio le permite simular, probar y reemplazar implementaciones fácilmente.

El enfoque correcto sería ocultar ContentProvider bajo una interfaz y hacer que el modelo acceda a los datos a través de esta interfaz. De esta manera, su código está desacoplado de la plataforma.

Básicamente, ContentProvider es la fuente de E / S que desea abstraer.

Repository Pattern es definido por Hieatt y Rob Mee como un patrón de diseño que media entre el dominio y las capas de mapeo de datos usando una interfaz tipo colección para acceder a objetos de dominio .

Básicamente, abstrae uno o más dispositivos de E / S (nube, disco, base de datos, etc.) en una interfaz similar a una colección común donde puede leer, escribir, buscar y eliminar datos .

En la arquitectura limpia de Android de Fernando Cejas , todos los datos necesarios para la aplicación provienen de esta capa mediante una implementación de repositorio (la interfaz está en la capa de dominio) que usa un patrón de repositorio con una estrategia que, a través de una fábrica, selecciona diferentes fuentes de datos dependiendo de ciertas condiciones.

Sin embargo, como señaló el profesor Douglas Schmidt en el curso de Coursera , el proveedor de contenido administra y media el acceso a un repositorio central de datos a una o más aplicaciones

En el libro Programación de Android , los proveedores de contenido se usan como fachada para un servicio web RESTful . Este enfoque fue presentado inicialmente por Virgil Dobjanschi durante Google I / O 2010 .

Por lo tanto, en lugar de utilizar proveedores de contenido para acceder a la base de datos SQLite local , ¿por qué no usarlo como el propio patrón de repositorio?


El proveedor de contenido es un componente de Android , el olor no será bueno si combina el concepto de repositorio con este componente, sino que crea una dependencia de bloqueo en su aplicación.


En mi humilde opinión, es mejor considerar a un proveedor de contenido como fuente de datos, aunque los datos se pueden almacenar de varias maneras (base de datos SQLite, archivos, ...), para mantener cierta independencia entre la arquitectura y el marco de Android.

Un repositorio de Google proporciona algunas muestras de arquitectura. Uno de ellos contiene un ejemplo de arquitectura con un proveedor de contenido y un repositorio:

googlesamples/android-architecture/todo-mvp-contentproviders

Extractos seleccionados:

Luego, puede usar proveedores de contenido para admitir características adicionales que no están cubiertas por esta muestra, que brinden los siguientes beneficios posibles:

  • Le permite compartir de forma segura los datos almacenados en su aplicación con otras aplicaciones.
  • Agregue soporte para búsquedas personalizadas en su aplicación.
  • Desarrolla widgets que acceden a los datos en tu aplicación.


Esa es una pregunta interesante. Creo que mi primera respuesta será no, el proveedor de contenido no es una implementación del patrón de repositorio.

Como mencionaste, el patrón de repositorio está destinado a separar la lógica comercial (dominio) de la capa de datos. Este enfoque le permite crear pruebas unitarias para su lógica de negocios (por lo que el dominio no debe depender en absoluto de Android). Al utilizar un proveedor de contenido, deberá tener algún tipo de objetos Android en su dominio.

Podría imaginarse una forma de ocultar la lógica del proveedor de contenido detrás de una interfaz, pero perderá muchas de las cosas agradables que un proveedor de contenido le permite hacer.

Si está interesado en la arquitectura de Android, le recomendaría que eche un vistazo a este proyecto de Github Android Clean Architecture . Encontrará una buena manera de separar su presentación, dominio y capa de datos, y la comunicación entre el dominio y los datos se realiza mediante el uso de un Patrón de repositorio.

Espero que esto ayude!


Felicitaciones por la pregunta, es una buena observación :). En mi humilde opinión, esta no es una pregunta de sí o no porque es bastante general, como lo son la mayoría de los temas relacionados con los patrones de diseño. La respuesta depende de qué contexto esté teniendo en cuenta:

Si tiene una aplicación que depende completamente de la plataforma, lo que significa que solo tiene en cuenta el contexto del ecosistema de Android, entonces sí, ContentProvider ES una implementación del patrón Repositorio . El argumento aquí es que el proveedor de contenido fue diseñado para resolver algunos de los mismos desafíos que los patrones de repositorio intentan resolver:

  • Proporciona abstracción sobre la capa de datos, por lo que el código no depende necesariamente del entorno de almacenamiento
  • Sin acceso directo a datos desde cualquier lugar. Puede poner todas sus consultas SQL (o lo que sea) en un solo lugar. Cuando implementé por primera vez un ContentProvider como novato, fue como una revelación para mí sobre cuán limpio puede parecer mi código y qué tan cómodo puedo estar haciendo los cambios.
  • Centraliza los datos y los comparte entre varios clientes (otras aplicaciones, un widget de búsqueda como ya sabe) y proporciona un mecanismo para la seguridad de los datos
  • Definitivamente puede definir el comportamiento relacionado con los datos (una forma es mediante el uso de ContentObserver)
  • Es una muy buena manera de forzarte desde las primeras etapas a organizar tu código con pruebas unitarias / pruebas automatizadas en mente

Si pone todo lo anterior junto a los principios del patrón de repositorio, hay algunas similitudes graves. No todos están satisfechos, pero las ideas centrales son las mismas.

Ahora, considerando una aplicación que trabaja en una escala mayor en múltiples entornos (es decir, web, móvil, PC), los requisitos cambian por completo. Es una mala idea ya que todos sugirieron confiar en ContentProvider como un patrón de diseño . No es necesariamente una mala idea en sí misma, pero se debe implementar un patrón de diseño para que otros puedan entender su código lo más rápido posible. Usted ve, incluso aquí todos sugirieron un uso común de ContentProvider: como fuente de datos, o de cualquier manera dependiente de la plataforma. Entonces, si fuerza una implementación sobre un componente con un propósito conocido, las cosas pueden volverse poco claras. Es mucho más agradable organizar tu código en un patrón clásico.

tl; dr; Si su aplicación está aislada en su dispositivo Android, definitivamente puede fusionar los dos conceptos. Si su aplicación se utiliza en una escala mayor, en múltiples plataformas es más limpio, para organizar su código de una manera clásica.


Mencionaré a Dianne Hackborn (del equipo de Android Framework) para dar mi opinión.

Proveedor de contenido

Finalmente, ContentProvider es una herramienta bastante especializada para publicar datos de una aplicación en otros lugares. La gente generalmente piensa en ellos como una abstracción en una base de datos, porque hay una gran cantidad de API y soporte integrado en ellos para ese caso común ... pero desde la perspectiva del diseño del sistema, ese no es su objetivo.

Lo que estos son para el sistema es un punto de entrada a una aplicación para publicar elementos de datos nombrados, identificados por un esquema de URI. Por lo tanto, una aplicación puede decidir cómo desea mapear los datos que contiene a un espacio de nombres de URI, entregando esos URI a otras entidades que a su vez pueden utilizarlos para acceder a los datos. Hay algunas cosas particulares que esto le permite al sistema hacer en la administración de una aplicación:

• La distribución de un URI no requiere que la aplicación siga en ejecución, por lo que puede ir por todas partes con la aplicación propietaria muerta. Solo en el punto donde alguien le dice al sistema, "oye, dame los datos para esta URI", necesita asegurarse de que la aplicación que posee esos datos se está ejecutando, por lo que puede solicitar a la aplicación que recupere y devuelva los datos.

• Estos URI también proporcionan un importante modelo de seguridad de grano fino. Por ejemplo, una aplicación puede colocar el URI para una imagen que tiene en el portapapeles, pero deja su proveedor de contenido bloqueado para que nadie pueda acceder libremente a él. Cuando otra aplicación extrae ese URI del portapapeles, el sistema puede otorgarle una "concesión de permiso URI" temporal para que se le permita acceder a los datos solo detrás de ese URI, pero nada más en la aplicación.

Lo que no nos importa

Realmente no importa cómo implemente la administración de datos detrás de un proveedor de contenido; si no necesita datos estructurados en una base de datos SQLite, no use SQLite. Por ejemplo, la clase de ayuda FileProvider es una manera fácil de hacer que los archivos brutos en su aplicación estén disponibles a través de un proveedor de contenido.

Además, si no está publicando datos de su aplicación para que otros la usen, no es necesario usar ningún proveedor de contenido. Es cierto, debido a los diversos ayudantes creados en torno a los proveedores de contenido, esta puede ser una manera fácil de colocar datos en una base de datos SQLite y usarlos para completar elementos de la IU como un ListView. Pero si alguna de estas cosas hace que lo que intentas hacer sea más difícil, no dudes en no utilizarlo y en su lugar utiliza un modelo de datos más apropiado para tu aplicación.

Texto completo aquí: https://plus.google.com/+DianneHackborn/posts/FXCCYxepsDU


Respuesta corta: un proveedor de contenido es un origen de datos y no un repositorio.

El propósito de SQL-Database / Android-Contentproviders / Repositories es crear / leer / actualizar / eliminar / buscar datos

Los repositorios generalmente operan en clases de Java específicas de alto nivel (como Cliente, Pedido, Producto, ...) mientras que los proveedores de Base de Datos SQL y Android operan en una tabla de bajo nivel, filas y columnas como fuente de datos .

Debido a que una base de datos SQL no es un repositorio, un proveedor de contenido de Android tampoco es un repositorio .

Pero puede implementar un repositorio utilizando un ContentProvider subyacente


Tratemos de comparar la definición de Patrón de repositorio del libro "Patrones de arquitectura de aplicaciones empresariales" por Martin Fowler (con Dave Rice, Matthew Foemmel, Edward Hieatt, Robert Mee y Randy Stafford) con lo que sabemos sobre ContentProviders .

El libro dice:

Un repositorio Media entre el dominio y las capas de mapeo de datos usando una interfaz tipo colección para acceder a objetos de dominio.

El bit importante es accessing domain objects . Por lo tanto, a primera vista, parece que el patrón de repositorio solo está destinado a acceder a (consultar) datos. Con ContentProvider , sin embargo, no solo puede acceder (leer) datos sino también insertar, actualizar o eliminar datos. Sin embargo, el libro dice:

Los objetos se pueden agregar y eliminar del Repositorio, como pueden hacerlo desde una simple colección de objetos, y el código de mapeo encapsulado por el Repositorio llevará a cabo las operaciones apropiadas detrás de las escenas.

Por lo tanto, sí Repository y ContentProvider parecen ofrecer las mismas operaciones (muy alto nivel de punto de vista) aunque el libro establece explícitamente la simple collection of objects que no es cierto para ContentProvider ya que requiere Android ContentValues y Cursor específicos del cliente (quien usa un cierto ContentProvider ) para interactuar con.

Además, el libro menciona domain objects y data mapping layers :

Un repositorio Media entre el dominio y las capas de mapeo de datos

y

En las portadas, el Repositorio combina Asignación de Metadatos (329) con un Objeto de Consulta (316) Asignación de Metadatos contiene detalles de la asignación objeto-relación en los metadatos.

La asignación de metadatos básicamente significa, es decir, cómo asignar una columna SQL a un campo de clase java.

Como ya se mencionó, ContentProvider devuelve un objeto Cursor de una operación query (). Desde mi punto de vista, un Cursor no es un objeto de dominio. Por otra parte, el mapeo del cursor al objeto de dominio debe ser realizado por el cliente (que usa un ContentProvider). Así que la asignación de datos falta por completo en ContentProvider desde mi punto de vista. Además, el cliente puede tener que usar ContentResolver también para obtener el objeto de dominio (datos). En mi opinión, esta API es una clara contradicción con la definición del libro:

El repositorio también es compatible con el objetivo de lograr una separación limpia y una dependencia de un solo sentido entre el dominio y las capas de mapeo de datos

Luego centrémonos en la idea central del patrón Repositorio:

En un sistema grande con muchos tipos de objetos de dominio y muchas consultas posibles, Repository reduce la cantidad de código necesario para hacer frente a todas las consultas que se realizan. Repository promueve el patrón de especificación (en forma del objeto de criterios en los ejemplos aquí), que encapsula la consulta que se realizará en una forma pura orientada a objetos. Por lo tanto, se puede eliminar todo el código para configurar un objeto de consulta en casos específicos. Los clientes nunca deben pensar en SQL y pueden escribir código puramente en términos de objetos.

ContentProvider requiere un URI (cadena). Entonces, no es realmente una "forma orientada a objetos". También un ContentProvider puede necesitar una projection y una where-clause .

Entonces, uno podría argumentar que una cadena URI es algún tipo de encapsulación, ya que el cliente puede usar esta cadena en lugar de escribir un código SQL específico, por ejemplo:

Con un Repositorio, el código del cliente construye los criterios y luego los pasa al Repositorio, pidiéndole que seleccione aquellos de sus objetos que coinciden. Desde la perspectiva del código del cliente, no hay ninguna noción de "ejecución" de consultas; más bien hay una selección de objetos apropiados a través de la "satisfacción" de la especificación de la consulta.

ContentProvider que usa un URI (cadena) no parece estar en contradicción con esa definición, pero aún echa de menos la manera enfática orientada a objetos. Además, las cadenas no son objetos de criterios reutilizables que se pueden reutilizar de forma general para componer la especificación de criterios para "reducir la cantidad de código necesario para hacer frente a todas las consultas que se realizan".

Por ejemplo, para buscar objetos personales por nombre, primero creamos un objeto de criterio, estableciendo cada criterio individual como: criterios.equals (Person.LAST_NAME, "Fowler") y criteria.like (Person.FIRST_NAME, "M"). Luego invocamos repository.matching (criterios) para devolver una lista de objetos de dominio que representan personas con el apellido Fowler y un primer nombre que comienza con M.

Como ya dijiste (en tu pregunta), el repositorio también es útil para ocultar diferentes fuentes de datos como un detalle de implementación que el cliente desconoce. Esto es cierto para ContentProviders y especificado en el libro:

El origen del objeto para el repositorio puede no ser una base de datos relacional en absoluto, lo que está bien ya que el repositorio se presta fácilmente para la sustitución del componente de mapeo de datos a través de objetos estratégicos especializados. Por esta razón, puede ser especialmente útil en sistemas con múltiples esquemas de bases de datos o fuentes para objetos de dominio, así como durante las pruebas cuando el uso de objetos exclusivamente en memoria es deseable para la velocidad.

y

Debido a que la interfaz del repositorio protege la capa de dominio del conocimiento de la fuente de datos, podemos refactorizar la implementación del código de consulta dentro del repositorio sin cambiar ninguna llamada de los clientes. De hecho, el código de dominio no necesita preocuparse por el origen o el destino de los objetos de dominio.

Entonces para concluir: algunas definiciones de Martin Fowler et al. libro coincide con la API de un proveedor de contenido (si ignora el hecho de que el libro enfatiza orientado a objetos):

  • Oculta el hecho de que un repositorio / ContentProvider tiene diferentes fuentes de datos
  • El cliente nunca tiene que escribir una consulta en un DSL específico de la fuente de datos como SQL. Eso es cierto para ContentProvider si consideramos que el URI no es específico de la fuente de datos.
  • Ambos, Repository y ContentProvider, tienen el mismo conjunto de operaciones de "alto nivel": leer, insertar, actualizar y eliminar datos (si ignoras el hecho de que Fowler habla mucho sobre objetos y colección de objetos, mientras que ContentProvider usa Cursor y ContentValues)

Sin embargo, ContentProvider realmente pierde algunos puntos clave del patrón de repositorio como se describe en el libro:

  • Dado que ContentProvider usa URI (también cadena para la cláusula where), un cliente no puede reutilizar los objetos de Criterios coincidentes. Eso es algo importante de notar. El libro dice claramente que el patrón del repositorio es útil "En un sistema grande con muchos tipos de objetos de dominio y muchas consultas posibles, el Repositorio reduce la cantidad de código necesario para hacer frente a todas las consultas que se realizan". Lamentablemente, ContentProvider no tiene objetos Criteria como criteria.equals(Person.LAST_NAME, "Fowler") que se pueden reutilizar y usar para redactar criterios de coincidencia (ya que debe usar cadenas).
  • ContentProvider omite por completo el mapeo de datos cuando devuelve un Cursor . Esto es muy malo porque un cliente (que usa un ContentProvider para acceder a los datos) tiene que hacer la asignación de Cursor al objeto de dominio. Además, eso significa que el cliente tiene conocimiento de las partes internas del repositorio, como el nombre de las columnas. "El repositorio puede ser un buen mecanismo para mejorar la legibilidad y la claridad en el código que utiliza consultas extensamente". Eso ciertamente no es cierto para ContentProviders.

Así que no, un ContentProvider no es una implementación del patrón Repository tal como se define en el Libro "Patrones de arquitectura de aplicaciones empresariales" porque omite al menos dos aspectos esenciales que he señalado anteriormente.

Además, tenga en cuenta que, como el nombre del libro ya sugiere, el patrón de repositorio está destinado a ser utilizado para aplicaciones empresariales donde realiza muchas consultas.

Los desarrolladores de Android tienden a usar el término "patrón de repositorio", pero en realidad no se refieren al patrón "original" descrito por Fowler et al. (alta reutilización de Criterios para consultas) sino una interfaz para ocultar la fuente de datos subyacente (SQL, Cloud, lo que sea) y la asignación de objetos de dominio.

Más aquí: http://hannesdorfmann.com/android/evolution-of-the-repository-pattern