延迟加载是一个概念,我们延迟加载对象,直到我们需要它的时候。
- 延迟加载只是在实际需要时初始化类的过程的一个花哨名称。
- 简单地说,延迟加载是一种软件设计模式,在这种模式中,对象的初始化只在实际需要时发生,而不是之前,以保持使用的简单性并提高性能。
- 当创建对象的成本非常高且很少使用对象时,延迟加载是必不可少的。因此,这是一个值得实现延迟加载的场景。延迟加载的基本思想是在需要时加载对象/数据。
例如,假设您正在创建一个应用程序,其中有一个Company对象,该对象在ContactList对象中包含该公司的员工列表。一家公司可能有数千名员工。从数据库中加载Company对象以及ContactList对象中所有员工的列表可能非常耗时。在某些情况下,你甚至不需要员工名单,但你不得不等到公司及其员工名单加载到内存中。 节省时间和内存的一种方法是在需要之前避免加载employee对象,这是使用 延迟加载设计模式 . 延迟加载模式有四种常见的实现:
- 虚拟代理
- 延迟初始化
- 鬼
- 价值持有者
虚拟代理
虚拟代理模式是一种节省内存的技术,建议将对象创建推迟到需要时。当创建一个在内存使用或所涉及的处理方面非常昂贵的对象时,可以使用它。
// 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主页上,并帮助其他极客。
如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。