0% encontró este documento útil (0 votos)
352 vistas12 páginas

Principios SOLID Con Ejemplos

Este documento describe los 5 principios SOLID de diseño de software (S - Single responsibility principle, O - Open/closed principle, L - Liskov substitution principle, I - Interface segregation principle, D - Dependency inversion principle). Explica cada principio con ejemplos sencillos y cómo aplicarlos facilita el mantenimiento del código y su legibilidad.

Cargado por

manuel_martin3
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
352 vistas12 páginas

Principios SOLID Con Ejemplos

Este documento describe los 5 principios SOLID de diseño de software (S - Single responsibility principle, O - Open/closed principle, L - Liskov substitution principle, I - Interface segregation principle, D - Dependency inversion principle). Explica cada principio con ejemplos sencillos y cómo aplicarlos facilita el mantenimiento del código y su legibilidad.

Cargado por

manuel_martin3
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

EN MI LOCAL FUNCIONA

Technical thoughts, stories and ideas

Principios SOLID
Publicado por Carlos Macías Martín el 03 April 2019

Best Practices Programacion SOLID

Todos sabemos que la POO (Programación Orientada a Objetos) nos permite agrupar entidades con funcionalidades
parecidas o relacionadas entre sí, pero esto no implica que los programas no se vuelvan confusos o difíciles de mantener.

De hecho, muchos programas acaban volviéndose un monstruo al que se va alimentando según se añaden nuevas
funcionalidades, se realiza mantenimiento, etc…

Viendo este problema, Robert C. Martin estableció cinco directrices o principios para facilitarnos a los desarrolladores la labor
de crear programas legibles y mantenibles.

Estos principios se llamaron S.O.L.I.D. por sus siglas en inglés:

S: Single responsibility principle o Principio de responsabilidad única

O: Open/closed principle o Principio de abierto/cerrado

L: Liskov substitution principle o Principio de sustitución de Liskov

I: Interface segregation principle o Principio de segregación de la interfaz

D: Dependency inversion principle o Principio de inversión de dependencia

Aplicar estos principios facilitará mucho el trabajo, tanto propio como ajeno (es muy probable que tu código lo acabe leyendo
muchos otros desarrolladores a lo largo de su ciclo de vida). Algunas de las ventajas de aplicarlo son:

Mantenimiento del código más fácil y rápido

Permite añadir nuevas funcionalidades de forma más sencilla

Favorece una mayor reusabilidad y calidad del código, así como la encapsulación
Vamos a ver en detalle cada uno de estos principios, junto a ejemplos básicos, que, a pesar de no ser aplicables en el mundo
real, espero que aporten la suficiente claridad para que seas capaz de entender y aplicar estos principios en tus desarrollos.

S: Principio de responsabilidad única

Como su propio nombre indica, establece que una clase, componente o microservicio debe ser responsable de una sola cosa (el
tan aclamado término “decoupled” en inglés). Si por el contrario, una clase tiene varias responsabilidades, esto implica que el
cambio en una responsabilidad provocará la modificación en otra responsabilidad.

Considera este ejemplo:

class Coche {

String marca;

Coche(String marca){ [Link] = marca; }

String getMarcaCoche(){ return marca; }

void guardarCocheDB(Coche coche){ ... }

¿Por qué este código viola el principio de responsabilidad única? Para un minuto y piensa un poco ;)

Como podemos observar, la clase Coche permite tanto el acceso a las propiedades de la clase como a realizar operaciones
sobre la BBDD, por lo que la clase ya tiene más de una responsabilidad.

Supongamos que debemos realizar cambios en los métodos que realizan las operaciones a la BBDD. En este caso, además de
estos cambios, probablemente tendríamos que tocar los nombres o tipos de las propiedades, métodos, etc, cosa que no parece
muy eficiente porque solo estamos modificando cosas que tienen que ver con la BBDD, ¿verdad?

Para evitar esto, debemos separar las responsabilidades de la clase, por lo que podemos crear otra clase que se encargue de las
operaciones a la BBDD:

class Coche {

String marca;

Coche(String marca){ [Link] = marca; }

String getMarcaCoche(){ return marca; }

class CocheDB{

void guardarCocheDB(Coche coche){ ... }

void eliminarCocheDB(Coche coche){ ... }

Nuestro programa será mucho más cohesivo y estará más encapsulado aplicando este principio.

O: Principio abierto/cerrado

Establece que las entidades software (clases, módulos y funciones) deberían estar abiertos para su extensión, pero cerrados
para su modificación.
Si seguimos con la clase Coche:

class Coche {

String marca;

Coche(String marca){ [Link] = marca; }

String getMarcaCoche(){ return marca; }

Si quisiéramos iterar a través de una lista de coches e imprimir sus marcas por pantalla:

public static void main(String[] args) {

Coche[] arrayCoches = {

new Coche("Renault"),

new Coche("Audi")

};

imprimirPrecioMedioCoche(arrayCoches);

public static void imprimirPrecioMedioCoche(Coche[] arrayCoches){

for (Coche coche : arrayCoches) {

if([Link]("Renault")) [Link](18000);

if([Link]("Audi")) [Link](25000);

Esto no cumpliría el principio abierto/cerrado, ya que si decidimos añadir un nuevo coche de otra marca:

Coche[] arrayCoches = {

new Coche("Renault"),

new Coche("Audi"),

new Coche("Mercedes")

};

También tendríamos que modificar el método que hemos creado anteriormente:

public static void imprimirPrecioMedioCoche(Coche[] arrayCoches){

for (Coche coche : arrayCoches) {

if([Link]("Renault")) [Link](18000);

if([Link]("Audi")) [Link](25000);

if([Link]("Mercedes")) [Link](27000);

Como podemos ver, para cada nuevo coche habría que añadir nueva lógica al método precioMedioCoche(). Esto es un ejemplo
sencillo, pero imagina que tu aplicación crece y crece… ¿cuántas modificaciones tendríamos que hacer? Mejor evitarnos esta
pérdida de tiempo y dolor de cabeza, ¿verdad?

Para que cumpla con este principio podríamos hacer lo siguiente:

abstract class Coche {

// ...

abstract int precioMedioCoche();

class Renault extends Coche {

@Override

int precioMedioCoche() { return 18000; }

class Audi extends Coche {

@Override

int precioMedioCoche() { return 25000; }

class Mercedes extends Coche {

@Override

int precioMedioCoche() { return 27000; }

public static void main(String[] args) {

Coche[] arrayCoches = {

new Renault(),

new Audi(),

new Mercedes()

};

imprimirPrecioMedioCoche(arrayCoches);

public static void imprimirPrecioMedioCoche(Coche[] arrayCoches){

for (Coche coche : arrayCoches) {

[Link]([Link]());

Cada coche extiende la clase abstracta Coche e implementa el método abstracto precioMedioCoche().

Así, cada coche tiene su propia implementación del método precioMedioCoche(), por lo que el método
imprimirPrecioMedioCoche() itera el array de coches y solo llama al método precioMedioCoche().

Ahora, si añadimos un nuevo coche, precioMedioCoche() no tendrá que ser modificado. Solo tendremos que añadir el nuevo
coche al array, cumpliendo así el principio abierto/cerrado.

L: Principio de substitución de Liskov

Declara que una subclase debe ser sustituible por su superclase, y si al hacer esto, el programa falla, estaremos violando este
principio.

Cumpliendo con este principio se confirmará que nuestro programa tiene una jerarquía de clases fácil de entender y un código
reutilizable.

Veamos un ejemplo:

// ...

public static void imprimirNumAsientos(Coche[] arrayCoches){

for (Coche coche : arrayCoches) {

if(coche instanceof Renault)


[Link](numAsientosRenault(coche));

if(coche instanceof Audi)

[Link](numAsientosAudi(coche));

if(coche instanceof Mercedes)

[Link](numAsientosMercedes(coche));

imprimirNumAsientos(arrayCoches);

Esto viola tanto el principio de substitución de Liskov como el de abierto/cerrado. El programa debe conocer cada tipo de
Coche y llamar a su método numAsientos() asociado.

Así, si añadimos un nuevo coche, el método debe modificarse para aceptarlo.


// ...

Coche[] arrayCoches = {

new Renault(),

new Audi(),

new Mercedes(),

new Ford()

};

public static void imprimirNumAsientos(Coche[] arrayCoches){

for (Coche coche : arrayCoches) {

if(coche instanceof Renault)


[Link](numAsientosRenault(coche));

if(coche instanceof Audi)

[Link](numAsientosAudi(coche));

if(coche instanceof Mercedes)

[Link](numAsientosMercedes(coche));

if(coche instanceof Ford)

[Link](numAsientosFord(coche));

imprimirNumAsientos(arrayCoches);

Para que este método cumpla con el principio, seguiremos estos principios:

Si la superclase (Coche) tiene un método que acepta un parámetro del tipo de la superclase (Coche), entonces su
subclase (Renault) debería aceptar como argumento un tipo de la superclase (Coche) o un tipo de la subclase (Renault).

Si la superclase devuelve un tipo de ella misma (Coche), entonces su subclase (Renault) debería devolver un tipo de la
superclase (Coche) o un tipo de la subclase (Renault).

Si volvemos a implementar el método anterior:

public static void imprimirNumAsientos(Coche[] arrayCoches){

for (Coche coche : arrayCoches) {

[Link]([Link]());

imprimirNumAsientos(arrayCoches);

Ahora al método no le importa el tipo de la clase, simplemente llama al método numAsientos() de la superclase. Solo sabe que
el parámetro es de tipo coche, ya sea Coche o alguna de las subclases.

Para esto, ahora la clase Coche debe definir el nuevo método:

abstract class Coche {

// ...

abstract int numAsientos();

Y las subclases deben implementar dicho método:

class Renault extends Coche {

// ...

@Override

int numAsientos() {

return 5;

// ...

Como podemos ver, ahora el método imprimirNumAsientos() no necesita saber con qué tipo de coche va a realizar su lógica,
simplemente llama al método numAsientos() del tipo Coche, ya que por contrato, una subclase de Coche debe implementar
dicho método.

I: Principio de segregación de interfaz

Este principio establece que los clientes no deberían verse forzados a depender de interfaces que no usan.

Dicho de otra manera, cuando un cliente depende de una clase que implementa una interfaz cuya funcionalidad este cliente no
usa, pero que otros clientes sí usan, este cliente estará siendo afectado por los cambios que fuercen otros clientes en dicha
interfaz.

Imaginemos que queremos definir las clases necesarias para albergar algunos tipos de aves. Por ejemplo, tendríamos loros,
tucanes y halcones:

interface IAve {

void volar();

void comer();

class Loro implements IAve{

@Override

public void volar() {

//...

@Override

public void comer() {

//..

class Tucan implements IAve{

@Override

public void volar() {

//...

@Override

public void comer() {

//..

Hasta aquí todo bien. Pero ahora imaginemos que queremos añadir a los pingüinos. Estos son aves, pero además tienen la
habilidad de nadar. Podríamos hacer esto:

interface IAve {

void volar();

void comer();

void nadar();

class Loro implements IAve{

@Override

public void volar() {

//...

@Override

public void comer() {

//...

@Override

public void nadar() {

//...

class Pinguino implements IAve{

@Override

public void volar() {

//...

@Override

public void comer() {

//...

@Override

public void nadar() {

//...

El problema es que el loro no nada, y el pingüino no vuela, por lo que tendríamos que añadir una excepción o aviso si se intenta
llamar a estos métodos. Además, si quisiéramos añadir otro método a la interfaz IAve, tendríamos que recorrer cada una de las
clases que la implementa e ir añadiendo la implementación de dicho método en todas ellas. Esto viola el principio de
segregación de interfaz, ya que estas clases (los clientes) no tienen por qué depender de métodos que no usan.

Lo más correcto sería segregar más las interfaces, tanto como sea necesario. En este caso podríamos hacer lo siguiente:

interface IAve {

void comer();

interface IAveVoladora {

void volar();

interface IAveNadadora {

void nadar();

class Loro implements IAve, IAveVoladora{

@Override

public void volar() {

//...

@Override

public void comer() {

//...

class Pinguino implements IAve, IAveNadadora{

@Override

public void nadar() {

//...

@Override

public void comer() {

//...

Así, cada clase implementa las interfaces de la que realmente necesita implementar sus métodos. A la hora de añadir nuevas
funcionalidades, esto nos ahorrará bastante tiempo, y además, cumplimos con el primer principio (Responsabilidad Única).
D: Principio de inversión de dependencias

Establece que las dependencias deben estar en las abstracciones, no en las concreciones. Es decir:

Los módulos de alto nivel no deberían depender de módulos de bajo nivel. Ambos deberían depender de abstracciones.

Las abstracciones no deberían depender de detalles. Los detalles deberían depender de abstracciones.

En algún momento nuestro programa o aplicación llegará a estar formado por muchos módulos. Cuando esto pase, es cuando
debemos usar inyección de dependencias, lo que nos permitirá controlar las funcionalidades desde un sitio concreto en vez de
tenerlas esparcidas por todo el programa. Además, este aislamiento nos permitirá realizar testing mucho más fácilmente.

Supongamos que tenemos una clase para realizar el acceso a datos, y lo hacemos a través de una BBDD:

class DatabaseService{

//...

void getDatos(){ //... }

class AccesoADatos {

private DatabaseService databaseService;

public AccesoADatos(DatabaseService databaseService){

[Link] = databaseService;

Dato getDatos(){

[Link]();

//...

Imaginemos que en el futuro queremos cambiar el servicio de BBDD por un servicio que conecta con una API. Para un minuto
a pensar qué habría que hacer... ¿Ves el problema? Tendríamos que ir modificando todas las instancias de la clase
AccesoADatos, una por una.

Esto es debido a que nuestro módulo de alto nivel (AccesoADatos) depende de un módulo de más bajo nivel
(DatabaseService), violando así el principio de inversión de dependencias. El módulo de alto nivel debería depender de
abstracciones.

Para arreglar esto, podemos hacer que el módulo AccesoADatos dependa de una abstracción más genérica:

interface Conexion {

Dato getDatos();

void setDatos();

class AccesoADatos {

private Conexion conexion;

public AccesoADatos(Conexion conexion){

[Link] = conexion;

Dato getDatos(){

[Link]();

Así, sin importar el tipo de conexión que se le pase al módulo AccesoADatos, ni este ni sus instancias tendrán que cambiar, por
lo que nos ahorraremos mucho trabajo.
Ahora, cada servicio que queramos pasar a AccesoADatos deberá implementar la interfaz Conexion:

class DatabaseService implements Conexion {

@Override

public Dato getDatos() { //... }

@Override

public void setDatos() { //... }

class APIService implements Conexion{

@Override

public Dato getDatos() { //... }

@Override

public void setDatos() { //... }

Así, tanto el módulo de alto nivel como el de bajo nivel dependen de abstracciones, por lo que cumplimos el principio de
inversión de dependencias. Además, esto nos forzará a cumplir el principio de Liskov, ya que los tipos derivados de Conexion
(DatabaseService y APIService) son sustituibles por su abstracción (interfaz Conexion).

Conclusión

Aplicar estos cinco principios puede parecer algo tedioso, pero a la larga, mediante la práctica y echarles un vistazo de vez en
cuando, se volverán parte de nuestra forma de programar.

Nuestro programa será más sencillo de mantener, pero no solo para nosotros, si no más aún para los desarrolladores que
vengan después, ya que verán un programa con una estructura bien definida y clara.

¿Conocías ya los principios SOLID? ¿los estabas aplicando en tu día a día? ¿los aplicarás? Me gustaría saber tu opinión.

Autor

CARLOS MACÍAS MARTÍN COMPARTE


Desarrollador de aplicaciones móviles, amante de la 


Compartir
tecnología, de compartir conocimientos y ayudar a los
demás.

TAMBIÉN EN EN MI LOCAL FUNCIONA

Usando Trivy desde Acelerando los Entendiendo CORS y Aprendiendo a ejecutar Aprendiendo
Azure DevOps desarrollos con … aplicando soluciones tests automatizados … Kafka (Parte 6
hace 3 meses • 1 comentario hace 2 años • 1 comentario hace 6 meses • 4 comentarios hace 2 años • 2 comentarios hace 2 años • 10 c

La seguridad es un aspecto En este artículo se va a En el desarrollo moderno de A principios de este año En este sexto ar
importante en el ciclo de mostrar como poder aplicaciones es común Amazon anunció la serie "Aprendien
vida del desarrollo de … disponer de unos … encontrarse con el … posibilidad de poder … Kafka" se va a d

26 Comentarios En mi local funciona 🔒 Política de privacidad de Disqus 


1 Acceder
 Favorite 24 t Tweet f Compartir Ordenar por los mejores

Únete a la conversación...

INICIAR SESIÓN CON


O REGISTRARSE CON DISQUS ?

Nombre

Carolina Grupico • hace 3 años


👏
1△ ▽ • Responder • Compartir ›

Armando Ruiz Gonzalez • hace 7 meses


Hola Carlos que excelente post. Muchas gracias :)
△ ▽ • Responder • Compartir ›

Joan Arturo • hace 7 meses


Excelente, me gusto la explicación
△ ▽ • Responder • Compartir ›

Andres Sebastian • hace 8 meses


recien entro en el mundo de la programación y tengo poca experiencia pero me podrias indicar que omitiste en el ejercicio de
responsabilidad única donde dejaste esos puntos "{...}"
△ ▽ • Responder • Compartir ›

ale jandro > Andres Sebastian • hace 8 meses • edited


Estimado @Andres Sebastian , a sintaxis utilzada en el ejemplo como "{...}" o "{// ...}" son en realidad una forma de simplificar
la explicación, para que no se extienda mucho en contenido.

E essas secciones iria el codigo fuente, con su aplicacion de negocio.

Asi si estas haciendo y/o siguiendo el ejemplo, podes colocar lo que quieras, como por ejemplo :

class CocheDB{
void guardarCocheDB(Coche coche){ [Link]("Guardando los datos"); }

void eliminarCocheDB(Coche coche){ [Link]("Eliminando los datos"); }

}
△ ▽ • Responder • Compartir ›

Jbot Trivitour • hace 9 meses


Desde el 2017... Hoy trabajo como calidad de código en codeReview y pocos conocen esto... Hablan de responsabilidad única pero de
palabritas. El de liskow es el más complicado explicar y exponer más cuando no saben de abstracción. SRP y OCP son los más
comunes. También me sorprende lo poco o nada sobre GRASP aunque aquí es otro tema ,,😃
△ ▽ • Responder • Compartir ›

David Morales • hace un año


Muy claro, gracias por los ejemplos me sirve bastante
△ ▽ • Responder • Compartir ›

RRS • hace un año


Muy sencillos y claros los ejemplos. Excelente!
△ ▽ • Responder • Compartir ›

j23 • hace 2 años


muy buen post, bien explicado y los ejemplos muy entendibles gracias
△ ▽ • Responder • Compartir ›

Lluis • hace 2 años


Muy buen articulo. Gracias Carlos.
△ ▽ • Responder • Compartir ›

Ray T.H. • hace 2 años


Excelente. No las conocía pero con tu explicación he entendido muy bien los principios.
Agradezco tu enseñanza y tus ganas de ayudar

Gracias!!!
△ ▽ • Responder • Compartir ›

Adrián Santos Mena • hace 2 años


Eres un grande


△ ▽ • Responder • Compartir ›

Ricardo • hace 2 años


muchas gracias por el articulo, me aclara muchas cosas, pero me quedo con una duda. cual es la diferencia entre el principio de
abierto/cerrado y el principio de sustitucion de liskov, los veo tan parecidos, ademas los ejemplo tambien me parecen similares.
△ ▽ • Responder • Compartir ›

Carlos Lopez > Ricardo • hace 2 años • edited


En el ejemplo de abierto/cerrado se usan ambos principios. El abierto/cerrado es simplemente extender una funcionalidad por
medio de herencia sin modificar el código ya existente, la sustitución de liskov es simplemente que todos los objetos que
heredan de una clase pueden ser usados como su clase padre. Es decir, para el ejemplo de abierto/cerrado, Renault, Merces y
Audi, se pueden tratar como Coche independientemente de su tipo extendido, como lo siguiente:

Coche coche = new Audi();

Si asi trato de acceder a las propiedades de audi, no seria posible ya que a pesar de ser una instancia de Audi, en el momento
solo es reconocido como Coche, por lo cual para poder acceder a dichas propiedades generalmente se hace un casting:

Audi audi = (Audi) coche;

Ahora audi sigue siendo el mismo objeto coche, pero con la capacidad de acceder las propiedades de Audi usando el objeto
audi.
△ ▽ • Responder • Compartir ›

Gonofokiu Maroon • hace 2 años


En el apartado de abierto/cerrado, si quisieramos agregar una nueva clase, por ej Ferrari, igual tendríamos que modificar la clase para
añadir el new Ferrari(); no? Eso sería una "modificación", sin embargo, es cierto que se ahorra la modificación de la impresión de los
precios, no me queda tan claro-

En el de Liskov, la implementación es clara pero, al final, cómo sabemos a qué coche le pertenece el número de asiento que nos está
imprimiendo? Igual me parece que está una maravilla, aún me cuesta un poco la inversión de dependencias, ya que no acabo de
entender al 100% la funcionalidad de las interfaces que son "instanciadas" en la clase que las va a usar para aplicar este concepto :/

Igualmente graaacias!
△ ▽ • Responder • Compartir ›

Jesús Utrera > Gonofokiu Maroon • hace 2 años


Hola. Si quieres añadir la clase "Ferrari", tienes que añadir una nueva clase Ferrari e instanciarla. Añades al código la nueva
instanciación, pero no modificas el comportamiento de ninguna otra clase. Imagina que la clase coche original implementa el
metodo "Acelerar". La aceleración depende de la presión del pedal del acelerador y de la aceleración del coche. Sin el principio
open/close, tienes que modificar para cada nuevo coche la forma de acelerar. Luego lo instancias en el main "Carrera" de igual
manera. Con el tiempo, el código se complicará debido a que metes variables nuevas que dependen de la propia marca de
coche y el código de la clase coche contendrá muchísimas líneas y posiblemente se convierta en un galimatías al depender de
muchas variables diferentes. Si crear una clase para cada marca siguiendo este principio, cada cambio lo vas a hacer el cada
clase de cada coche sin que estas variables afecten a tu código que tendría que controlarlas dependiendo de la marca (te
centras en qué hace una marca independientemente del resto) y cuando una marca concreta tenga una nueva modificación
(por ejemplo usar una tecnología nueva única), lo vas a programar sólo en esa clase.

Espero haber podido ayudarte.


△ ▽ • Responder • Compartir ›

Jhonnatan • hace 3 años


Gracias por el post, ahora pude entenderlo mejor.
△ ▽ • Responder • Compartir ›

Carlos Macías > Jhonnatan • hace 3 años


Me alegro que te haya ayudado Jhonnatan :)
△ ▽ • Responder • Compartir ›

alfirian777 • hace 3 años


Chulada de artículo
△ ▽ • Responder • Compartir ›

Carlos Macías > alfirian777 • hace 3 años


Muchas gracias, me alegro que te guste! :)
• Responder • Compartir ›

Ricardo Moreno Hernández • hace 3 años


Genial el artículo! Los ejemplos son muy acertados para explicar cada principio. Sin ninguna duda los aplicaré, en mi caso empleando
el lenguaje PHP. Muchas gracias por compartir esta información :)
△ ▽ • Responder • Compartir ›

Emmanuel Valverde Ramos > Ricardo Moreno Hernández • hace un año


Si quieres más información pero con ejemplos de PHP puedes ver mi post en [Link]

[Link]
△ ▽ • Responder • Compartir ›

Carlos Macías > Ricardo Moreno Hernández • hace 3 años


Gracias a ti por tus palabras Ricardo! lo bueno es que estos principios son aplicable a cualquier lenguaje de programación :)

Un saludo! :)
△ ▽ • Responder • Compartir ›

Jesús Utrera • hace 3 años


Muy buen artículos con buenos ejemplos.
△ ▽ • Responder • Compartir ›

Carlos Macías > Jesús Utrera • hace 3 años


Gracias Jesús! Me alegro que te guste :)
△ ▽ • Responder • Compartir ›

Jose Carlos > Carlos Macías • hace 3 años


articulo buenísimo con ejemplos claros y oportunos
△ ▽ • Responder • Compartir ›

✉ Suscríbete d Añade Disqus a tu sitio webAñade Disqus Añadir ⚠ Do Not Sell My Data

Condiciones de Uso
Powered by atSistemas

EN MI LOCAL FUNC (http://enmilocalfunciona.io/)IONA
Technical thoughts, stories and ideas
Principios SOLID (https://enmilocal
Vamos a ver en detalle cada uno de estos principios, junto a ejemplos básicos, que, a pesar de no ser aplicables en el mundo
Si seguimos con la clase Coche:
class Coche {  
    String marca;
    Coche(String marca){ this.marca = marca; }
    String g
}
class Audi extends Coche {  
    @Override
    int precioMedioCoche() { return 25000; }
}
class Mercedes extends Coche {
// ...
Coche[] arrayCoches = {  
        new Renault(),
        new Audi(),
        new Mercedes(),
        new Ford()
};
pub
Como podemos ver, ahora el método imprimirNumAsientos() no necesita saber con qué tipo de coche va a realizar su lógica,
simp
@Override
    public void nadar() {
        //...
    }
}
class Pinguino implements IAve{
    @Override
    public void v
D: Principio de inversión de dependencias
Establece que las dependencias deben estar en las abstracciones, no en las concreci
Ahora, cada servicio que queramos pasar a AccesoADatos deberá implementar la interfaz Conexion:
class DatabaseService impleme
(https://disqus.com/by/adrinsantosmena/) (https://disqus.com/by/ray_t_h/) (https://disqus.com/by/disqus_cXKy6CvEqd/) (https:

También podría gustarte