I do not understand the second and third principles of solid

2

Single Responsibility: each object must have a unique responsibility Open / Close: open for extension, closed before changes

Liskov Substitution: daughter classes should be able to be treated as parent classes

Segregation interface: many interfaces with few methods are preferable to few interfaces with many methods

Dependency Inversion: components must depend on abstractions, not concrete implementations

Someone who knows can explain me?

    
asked by hubman 12.11.2016 в 04:02
source

3 answers

4

Open / Close: It means that you have to make a design so that, when adding new functionality, you do not have to touch the existing code.

Imagine that you have a billing application and several types of clients, defined in an enum, and to invoice you do something like:

switch (cliente.getTipoCliente) {
case TipoClienteA:
   facturarClienteA(cliente);
   break;
case TipoClienteB:
   facturarClienteB(cliente);
   break;

If you add a type of client, you have to go to all client-type switches and ifs and add the logic, modifying code that already works.

As an alternative, imagine that you define an interface Facturador , and that in the enum of TypeClient you have a method that, for each instance, gives you an implementation of Facturador appropriate to the type of client. Then the above code looks like:

Facturador facturador = cliente.getTipoCliente.getFacturador();
facturador.facturarCliente(cliente);

If you add a new client, you only need to implement the invoice and add the element to the enum.

Other options are plugin systems and so on.

Having said that, I have always found that it is the most complicated criterion to implement, and I apply it only for well-defined blocks (remember that SOLID are recommendations, not absolute rules).

The substitution principle is that an instance of a subclass must always function consistently as an instance of the superclass would. For example, imagine
 public class A {

   public int valorAbsoluto(int val) {
     return val < 0 ? -val : val;
   }
 }

 public class B extends A {
   @Override
   public int valorAbsoluto(int val) {
     return 0;
   }
 }

It does not make much sense, right? If you pass an instance of B to a method x that accepts a A , you may end up having a DivideByCeroError even though x has made the correct checks.

The problem is that the instance of B does not act as an instance of A , even though it is also an instance of A (because it is an instance of a subclass of A ).

Liskov's principle adds that, in addition, history must be taken into account. Imagine that each B method complies with the A implementation, with the exception that after calling each B method you must call a reset() method, or that the B methods should be called in a certain order. A code that expects to use instances of A will not take those restrictions into account, which will again result in unexpected / erroneous results.

    
answered by 12.11.2016 / 11:55
source
4

Single Responsibility or SRP Each object must have a unique responsibility, this can be translated or applied as: Each object must have a unique reason to change, to explain this better, let's see the following example, suppose we have the Next class Client that is in charge of storing a client in the database:

public class ServicioCliente
{
    private ClienteDb _clienteAccesoADatos = new ClienteDb();

    public void GuardarCliente(Cliente entidad)
    {
         if(!ValidarCliente(entidad))
              throw new InvalidOperationException("El cliente no es válido");

         _clienteAccesoADatos.Guardar(entidad)
    }

    public bool ValidarCliente(Cliente entidad)
    {
        bool resultado = true;
        if(string.IsNullOrWhiteSpace(entidad.Nombre))
           result &= false;
        if(string.IsNullOrWhiteSpace(entidad.Apellidos))
           result &= false;

        return resultado;
   }
}

In this case our class does 2 things:

  • Verify that the client is valid.
  • Stores the client in the database.
  • Which means that if we want to change something we have 2 reasons to change the class so we are violating the principle of Single Responsibility (from now on SRP) In this case what we can do is divide our class into two classes. In this way:

    public class ServicioCliente
    {
        private ClienteDb _clienteAccesoADatos = new ClienteDb();
        private ValidadorCliente _validador = new ValidadorCliente();
    
        public void GuardarCliente(Cliente entidad)
        {
             if(!_validador.ValidarCliente(entidad))
                  throw new InvalidOperationException("El cliente no es válido");
    
             _clienteAccesoADatos.Guardar(entidad)
        }        
    }
    
    Internal class ValidadorCliente
    {
        public bool ValidarCliente(Cliente entidad)
        {
            bool resultado = true;
            if(string.IsNullOrWhiteSpace(entidad.Nombre))
               result &= false;
            if(string.IsNullOrWhiteSpace(entidad.Apellidos))
               result &= false;
    
            return resultado;
       }
    }
    

    In this way we now have two classes that have only one reason to be changed.

  • Change the storage method for the Client Service case
  • Change the validation form for the Customer Validator case
  • While this principle usually applies to classes, it can also be applied to methods in a class. A good way to detect if you are complying with the SRP principle is by adding comments on what a method / class does, see the following example:

     public void GuardarCliente(Cliente entidad)
        {
             bool esValido = true;
             // Verifica si el cliente es válido
             if(string.IsNullOrWhiteSpace(entidad.Nombre)
                  esValido = false;
             if(string.IsNullOrWhiteSpace(entidad.Apellidos)
                 esValido = false;
             if(entidad.edad < 18)
                 esValido = false;
    
             // Busca en la base de datos si el cliente existe
             Cliente cliente = __clienteAccesoADatos.ObtenerPrimero(entidad.Id);
             if(cliente != null) 
                    throw new InvalidOperationException("El cliente ya existe");
    
             if(!esValido)
                   throw new InvalidOperationException("El cliente es inválido");
             // guarda el cliente             
             _clienteAccesoADatos.Guardar(entidad)
        }       
    

    As we can see in the comments, this method currently has 3 responsibilities:

  • Verify that the client is valid
  • Check if the client is in the database
  • Save the customer in the database
  • For what also violates the SRP, in this case like the previous one we will have to separate the method in smaller methods that have a single responsibility and then do the same with the class.

    I hope this will clarify the principle of sole responsibility. I have nothing to add to the other principles.

    Greetings.

        
    answered by 23.04.2017 в 03:52
    3

    Single Responsibility: each object must have a single responsibility Open / Close: open for extension, closed to changes

    More or less it means that when you go to create a class, you only have to have the methods that will be used in x functionality. and do not declare all the methods that will be used in the system.

    This principle tries to assign each class to a simple and concrete purpose.

    Interface Segregation: This means that if a user does not need an interface, do not oblige to use it.

    Here I leave a link that explains very well the principles of solid

    link

        
    answered by 12.11.2016 в 09:41