Patrón de diseño de carga perezosa

Lazy loading es un concepto en el que retrasamos la carga del objeto hasta el punto en que lo necesitamos.

  • Lazy loading es solo un nombre elegante que se le da al proceso de inicializar una clase cuando realmente se necesita.
  • En palabras simples, Lazy loading es un patrón de diseño de software donde la inicialización de un objeto ocurre solo cuando realmente se necesita y no antes para preservar la simplicidad de uso y mejorar el rendimiento.
  • La carga diferida es esencial cuando el costo de creación del objeto es muy alto y el uso del objeto es muy raro. Así que este es el escenario en el que vale la pena implementar la carga diferida. La idea fundamental de la carga diferida es cargar objetos/datos cuando sea necesario.

Por ejemplo, suponga que está creando una aplicación en la que hay un objeto Company y este objeto contiene una lista de empleados de la empresa en un objeto ContactList. Podría haber miles de empleados en una empresa. Cargar el objeto Company desde la base de datos junto con la lista de todos sus empleados en el objeto ContactList podría llevar mucho tiempo. En algunos casos ni siquiera requiere la lista de los empleados, sino que se ve obligado a esperar hasta que la empresa y su lista de empleados se carguen en la memoria.
Una forma de ahorrar tiempo y memoria es evitar la carga de los objetos de empleado hasta que sea necesario y esto se hace mediante el patrón de diseño de carga diferida . Hay cuatro implementaciones comunes del patrón Lazy Loading:
Lazy_Loading1

  1. proxy virtual
  2. Inicialización perezosa
  3. Fantasma
  4. Titular de valor

proxy virtual

El patrón de proxy virtual es una técnica de ahorro de memoria que recomienda posponer la creación de un objeto hasta que se necesite. Se usa cuando se crea un objeto que es costoso en términos de uso de memoria o procesamiento involucrado.

// Java program to illustrate
// virtual proxy in
// Lazy Loading Design Pattern
import java.util.List;
import java.util.ArrayList;
  
interface ContactList
{
public List<Employee> getEmployeeList();
}
  
class Company {
    String companyName;
    String companyAddress;
    String companyContactNo;
    ContactList contactList;
  
    public Company(String companyName, String companyAddress,
            String companyContactNo, ContactList contactList)
    {
        this.companyName = companyName;
        this.companyAddress = companyAddress;
        this.companyContactNo = companyContactNo;
        this.contactList = contactList;
    }
  
    public String getCompanyName()
    {
        return companyName;
    }
    public String getCompanyAddress()
    {
        return companyAddress;
    }
    public String getCompanyContactNo()
    {
        return companyContactNo;
    }
    public ContactList getContactList()
    {
        return contactList;
    }
  
}
  
class ContactListImpl implements ContactList {
    public List<Employee> getEmployeeList()
    {
        return getEmpList();
    }
    private static List<Employee> getEmpList()
    {
        List<Employee> empList = new ArrayList<Employee>(5);
  
        empList.add(new Employee("Lokesh", 2565.55, "SE"));
        empList.add(new Employee("Kushagra", 22574, "Manager"));
        empList.add(new Employee("Susmit", 3256.77, "G4"));
        empList.add(new Employee("Vikram", 4875.54, "SSE"));
        empList.add(new Employee("Achint", 2847.01, "SE"));
  
        return empList;
    }
}
  
class ContactListProxyImpl implements ContactList {
    private ContactList contactList;
    public List<Employee> getEmployeeList()
    {
        if (contactList == null) {
            System.out.println("Fetching list of employees");
            contactList = new ContactListImpl();
        }
        return contactList.getEmployeeList();
    }
}
  
class Employee {
    private String employeeName;
  
    private double employeeSalary;
    private String employeeDesignation;
  
    public Employee(String employeeName,
             double employeeSalary, String employeeDesignation)
    {
        this.employeeName = employeeName;
        this.employeeSalary = employeeSalary;
        this.employeeDesignation = employeeDesignation;
    }
    public String getEmployeeName()
    {
        return employeeName;
    }
    public double getEmployeeSalary()
    {
        return employeeSalary;
    }
    public String getEmployeeDesignation()
    {
        return employeeDesignation;
    }
    public String toString()
    {
        return "Employee Name: " + employeeName + ", 
               EmployeeDesignation : " + employeeDesignation + ",
               Employee Salary : " + employeeSalary;
    }
}
  
class LazyLoading {
    public static void main(String[] args)
    {
        ContactList contactList = new ContactListProxyImpl();
        Company company = new Company
        ("Geeksforgeeks", "India", "+91-011-28458965", contactList);
  
        System.out.println("Company Name: " + company.getCompanyName());
        System.out.println("Company Address: " + company.getCompanyAddress());
        System.out.println("Company Contact No.: " + company.getCompanyContactNo());
        System.out.println("Requesting for contact list");
  
        contactList = company.getContactList();
        List<Employee> empList = contactList.getEmployeeList();
        for (Employee emp : empList) {
            System.out.println(emp);
        }
    }
}

Producción:

Company Name: ABC Company
Company Address: India
Company Contact No.: +91-011-28458965
Requesting for contact list
Fetching list of employees
Employee Name: Lokesh, EmployeeDesignation: SE, Employee Salary: 2565.55
Employee Name: Kushagra, EmployeeDesignation: Manager, Employee Salary: 22574.0
Employee Name: Susmit, EmployeeDesignation: G4, Employee Salary: 3256.77
Employee Name: Vikram, EmployeeDesignation: SSE, Employee Salary: 4875.54
Employee Name: Achint, EmployeeDesignation: SE, Employee Salary: 2847.01

Ahora, en el código anterior, se crea un objeto Company con un objeto ContactList de proxy. En este momento, el objeto Company tiene una referencia de proxy, no la referencia del objeto ContactList real, por lo que no hay una lista de empleados cargada en la memoria.

Inicialización perezosa

La técnica de Lazy Initialization consiste en comprobar el valor de un campo de clase cuando se está utilizando. Si ese valor es igual a nulo, ese campo se carga con el valor adecuado antes de que se devuelva.
Aquí está el ejemplo:

// Java program to illustrate
// Lazy Initialization in
// Lazy Loading Design Pattern
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
  
enum CarType {
    none,
    Audi,
    BMW,
}
  
class Car {
    private static Map<CarType, Car> types = new HashMap<>();
  
    private Car(CarType type) {}
  
    public static Car getCarByTypeName(CarType type)
    {
        Car Car;
  
        if (!types.containsKey(type)) {
            // Lazy initialisation
            Car = new Car(type);
            types.put(type, Car);
        } else {
            // It's available currently
            Car = types.get(type);
        }
  
        return Car;
    }
  
    public static Car getCarByTypeNameHighConcurrentVersion(CarType type)
    {
        if (!types.containsKey(type)) {
            synchronized(types)
            {
                // Check again, after having acquired the lock to make sure
                // the instance was not created meanwhile by another thread
                if (!types.containsKey(type)) {
                    // Lazy initialisation
                    types.put(type, new Car(type));
                }
            }
        }
  
        return types.get(type);
    }
  
    public static void showAll()
    {
        if (types.size() > 0) {
  
            System.out.println("Number of instances made = " + types.size());
  
            for (Entry<CarType, Car> entry : types.entrySet()) {
                String Car = entry.getKey().toString();
                Car = Character.toUpperCase(Car.charAt(0)) + Car.substring(1);
                System.out.println(Car);
            }
  
            System.out.println();
        }
    }
}
  
class Program {
    public static void main(String[] args)
    {
        Car.getCarByTypeName(CarType.BMW);
        Car.showAll();
        Car.getCarByTypeName(CarType.Audi);
        Car.showAll();
        Car.getCarByTypeName(CarType.BMW);
        Car.showAll();
    }
}

Producción :

Number of instances made = 1
BMW

Number of instances made = 2
BMW
Audi

Number of instances made = 2
BMW
Audi

Titular del valor

Básicamente, un titular de valor es un objeto genérico que maneja el comportamiento de carga diferida y aparece en lugar de los campos de datos del objeto. Cuando el usuario necesita acceder a él, simplemente le pregunta al titular de valor por su valor llamando al método GetValue. En ese momento (y solo entonces), el valor se carga desde una base de datos o desde un servicio (esto no siempre es necesario).

// Java function to illustrate
// Lazy Initialization in
// Lazy Loading Design Pattern
public class ValueHolder<T> {
    private T value;
    private readonly Func<object, T> valueRetrieval;
  
    // Constructor
    public ValueHolder(Func<object, T> valueRetrieval)
    {
        valueRetrieval = this.valueRetrieval;
    }
  
    // We'll use the signature "GetValue" for convention
    public T GetValue(object parameter)
    {
        if (value == null)
            value = valueRetrieval(parameter);
        return value;
    }
}

Nota: El principal inconveniente de este enfoque es que el usuario debe saber que se espera un titular de valor.

Fantasma

Un fantasma es el objeto que se va a cargar en un estado parcial. Corresponde al objeto real pero no en su estado completo. Puede estar vacío o puede contener solo algunos campos (como el ID). Cuando el usuario intenta acceder a algunos campos que aún no se han cargado, el objeto fantasma se inicializa por completo (esto no siempre es necesario).

Por ejemplo, supongamos que un desarrollador agrega un formulario en línea para que cualquier usuario pueda solicitar contenido a través de ese formulario en línea. En el momento de la creación, todo lo que sabemos es que se accederá al contenido, pero el usuario desconoce qué acción o contenido.

$userData = array(
    "UID" = > uniqid(),
    "requestTime" = > microtime(true),
    "dataType" = > "",
    "request" = > "");
  
if (isset($_POST['data']) && $userData) {
    //...
}

En el ejemplo de PHP anterior, el usuario puede acceder al contenido del formulario en línea en forma de archivo de texto o cualquier fuente.

  • UID es la identificación única para cada usuario en particular.
  • requestTime es el momento en que el usuario solicitó el contenido del formulario en línea.
  • dataType es el tipo de datos. En su mayoría es texto, pero depende de la forma.
  • request es la función booleana para notificar al usuario sobre la finalización o no de la solicitud.

Ventajas

  • Este enfoque es un tiempo de inicio de la aplicación más rápido, ya que no es necesario crear y cargar todos los objetos de la aplicación.

Desventajas

  • El código se vuelve complicado ya que necesitamos verificar si se necesita cargar o no. Por lo tanto, esto puede causar un rendimiento más lento.

Este artículo es una contribución de Saket Kumar . Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo usando contribuya.geeksforgeeks.org o envíe su artículo por correo a contribuya@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.

Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *