延迟加载设计模式

延迟加载是一个概念,我们延迟加载对象,直到我们需要它的时候。

null
  • 延迟加载只是在实际需要时初始化类的过程的一个花哨名称。
  • 简单地说,延迟加载是一种软件设计模式,在这种模式中,对象的初始化只在实际需要时发生,而不是之前,以保持使用的简单性并提高性能。
  • 当创建对象的成本非常高且很少使用对象时,延迟加载是必不可少的。因此,这是一个值得实现延迟加载的场景。延迟加载的基本思想是在需要时加载对象/数据。

例如,假设您正在创建一个应用程序,其中有一个Company对象,该对象在ContactList对象中包含该公司的员工列表。一家公司可能有数千名员工。从数据库中加载Company对象以及ContactList对象中所有员工的列表可能非常耗时。在某些情况下,你甚至不需要员工名单,但你不得不等到公司及其员工名单加载到内存中。 节省时间和内存的一种方法是在需要之前避免加载employee对象,这是使用 延迟加载设计模式 . Lazy_Loading1 延迟加载模式有四种常见的实现:

  1. 虚拟代理
  2. 延迟初始化
  3. 价值持有者

虚拟代理

虚拟代理模式是一种节省内存的技术,建议将对象创建推迟到需要时。当创建一个在内存使用或所涉及的处理方面非常昂贵的对象时,可以使用它。

// 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);
}
}
}


输出:

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

现在,在上面的代码中,使用代理联系人列表对象创建了一个Company对象。此时,Company对象持有一个代理引用,而不是真正的ContactList对象的引用,因此内存中没有加载员工列表。

延迟初始化

惰性初始化技术包括在使用类字段时检查其值。如果该值等于null,则在返回该字段之前,该字段将加载正确的值。 下面是一个例子:

// 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();
}
}


输出:

Number of instances made = 1
BMW

Number of instances made = 2
BMW
Audi

Number of instances made = 2
BMW
Audi

价值持有者

基本上,值持有者是一个处理延迟加载行为的通用对象,它出现在对象的数据字段中。当用户需要访问它时,他们只需通过调用GetValue方法向值持有者请求其值。在那个时候(而且只有在那个时候),该值才能从数据库或服务中加载。(这并不总是需要的)。

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


注意:这种方法的主要缺点是,用户必须知道预期会有一个值持有者。

重影是要以部分状态加载的对象。它对应于真实对象,但不处于完整状态。它可能是空的,也可能只包含一些字段(例如ID)。当用户试图访问一些尚未加载的字段时,ghost对象会完全初始化自身(并不总是需要)。

例如,让我们考虑开发人员添加了一个在线表单,以便任何用户可以通过该在线表单请求内容。在创建时,我们只知道内容将被访问,但用户不知道什么操作或内容。

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


在上面的PHP示例中,用户可以以文本文件或任何源的形式访问在线表单中的内容。

  • 液体 是每个特定用户的唯一id。
  • 请求时间 是用户从在线表单请求内容的时间。
  • 数据库类型 是数据的类型。主要是文本,但取决于形式。
  • 要求 是一个布尔函数,用于通知用户请求是否已完成。

优势

  • 这种方法可以更快地启动应用程序,因为不需要创建和加载所有应用程序对象。

缺点

  • 代码变得复杂,因为我们需要检查是否需要加载。因此,这可能会导致性能降低。

本文由 萨凯特·库马尔 .如果你喜欢GeekSforgek,并想贡献自己的力量,你也可以使用 贡献极客。组织 或者把你的文章寄到contribute@geeksforgeeks.org.看到你的文章出现在Geeksforgeks主页上,并帮助其他极客。

如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享