• 深入浅出设计模式之-代理模式
  • 发布于 2个月前
  • 359 热度
    0 评论
在日常开发中,我们往往忽视了设计模式的重要性。这可能是因为项目时间紧迫,或者对设计模式理解不深。其实,很多时候我们可能在不经意间已经使用了某些模式。重要的是要有意识地学习和应用,让代码更加优雅和高效。也许是时候重新审视我们的编程实践,将设计模式融入其中了。今天由浅入深,重学【代理模式】,让我们一起“重学设计模式”。

一、代理模式
代理模式是一种结构型设计模式,通过为另外一个对象提供一个替代或占位符,以控制对该对象的访问。代理模式在客户端与目标对象之间引入一个代理对象,可以在不改变目标对象的情况下,增加额外的功能,如权限控制、懒加载、日志记录等。

1、代理模式的结构
Subject(抽象主题):定义目标对象和代理对象的共同接口。
RealSubject(真实主题):实现Subject接口,是真正执行任务的对象。
Proxy(代理):实现Subject接口,持有一个RealSubject的引用,并控制对RealSubject的访问。

2、代理模式简要代码
// 抽象主题
interface Subject {
    void request();
}

// 真实主题
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: Handling request.");
    }
}
// 堆代码 duidaima.com
// 代理
class ProxySubject implements Subject {
    private RealSubject realSubject;

    @Override
    public void request() {
        if (realSubject == null) {
            realSubject = new RealSubject();
        }
        System.out.println("ProxySubject: Logging before request.");
        realSubject.request();
        System.out.println("ProxySubject: Logging after request.");
    }
}
假设开发一个图像查看器应用,需要加载和显示大量图像。直接加载所有图像会占用大量内存和时间。通过代理模式,可以在需要显示图像时才加载实际的图像对象。

二、不用代理模式
public class Image {
    private String filename;
    public Image(String filename) {
        this.filename = filename;
        loadImageFromDisk();
    }
    private void loadImageFromDisk() {
        System.out.println("Loading image: " + filename);
    }
    public void display() {
        System.out.println("Displaying image: " + filename);
    }
}
public class Client {
    public static void main(String[] args) {
        Image image1 = new Image("image1.jpg");
        Image image2 = new Image("image2.jpg");
        image1.display();
        image2.display();
    }
}

三、使用代理模式
1、抽象主题
/**
 * 代理模式
 *
 * 抽象主题
 */
public interface Image {
    void display();
}
2、真实主题
/**
 * 真实主题
 */
public class RealImage implements Image {
    private String filename;
    public RealImage(String filename) {
        this.filename = filename;
        loadImageFromDisk();
    }
    private void loadImageFromDisk() {
        System.out.println("Loading image: " + filename);
    }
    @Override
    public void display() {
        System.out.println("Displaying image: " + filename);
    }
}
3、代理
public class ProxyImage implements Image {

    private RealImage realImage;
    private String filename;

    public ProxyImage(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}
4、客户端
public class ProxyClient {
    public static void main(String[] args) {
        Image image1 = new ProxyImage("image1.jpg");
        Image image2 = new ProxyImage("image2.jpg");
        // 图像将在显示时加载
        image1.display();
        image2.display();
    }
}

5、使用代理模式有哪些改进和优化?
(1)延迟加载
图像只有在需要显示时才加载,节省资源。

(2)降低内存使用
避免一次性加载所有图像,适用于大量对象场景。

(3)增强控制
代理可以在加载前后添加额外逻辑,如缓存、权限检查。

四、哪些场景可以使用代理模式优化?
虚拟代理:延迟对象的创建和初始化。
保护代理:控制对对象的访问权限。
远程代理:为远程对象提供本地代表。
智能代理:在访问对象时执行附加操作,如引用计数、日志记录。
Java代码举例:远程代理
// 抽象主题
interface Image {
    void display();
}

// 真实主题
class RealImage implements Image {
    private String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadImageFromServer();
    }

    private void loadImageFromServer() {
        System.out.println("Loading image from server: " + filename);
    }

    @Override
    public void display() {
        System.out.println("Displaying image: " + filename);
    }
}

// 代理
class RemoteImageProxy implements Image {
    private RealImage realImage;
    private String filename;

    public RemoteImageProxy(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}

// 客户端代码
public class RemoteProxyClient {
    public static void main(String[] args) {
        Image image = new RemoteImageProxy("remoteImage.jpg");
        image.display();
    }
}
五、在JDK源码中,哪些地方应用了代理模式
1、java.lang.reflect.Proxy 类
使用动态代理机制,为接口创建代理实例,允许在运行时动态处理方法调用。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 接口
interface Service {
    void perform();
}

// 真实主题
class ServiceImpl implements Service {
    @Override
    public void perform() {
        System.out.println("ServiceImpl: Performing service.");
    }
}

// 代理处理器
class ServiceInvocationHandler implements InvocationHandler {
    private Service service;

    public ServiceInvocationHandler(Service service) {
        this.service = service;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Proxy: Before method " + method.getName());
        Object result = method.invoke(service, args);
        System.out.println("Proxy: After method " + method.getName());
        return result;
    }
}

// 客户端代码
public class ProxyExample {
    public static void main(String[] args) {
        Service realService = new ServiceImpl();
        Service proxyService = (Service) Proxy.newProxyInstance(
            realService.getClass().getClassLoader(),
            realService.getClass().getInterfaces(),
            new ServiceInvocationHandler(realService)
        );
        proxyService.perform();
    }
}
2、java.io.BufferedInputStream 类
通过代理模式包装原始的输入流,增加缓冲功能,提高读写效率。
BufferedInputStream 作为代理,封装了 FileInputStream,提供了缓冲功能,优化了文件读取操作。
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class BufferedInputStreamExample {
    public static void main(String[] args) {
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("file.txt"))) {
            int data;
            while ((data = bis.read()) != -1) {
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
六、总结
代理模式通过在客户端与真实对象之间引入代理对象,控制和管理对真实对象的访问,实现功能扩展和优化。其结构包括抽象主题、真实主题和代理三个部分,能够在不修改目标对象的情况下,添加如懒加载、权限控制、日志记录等额外功能。代理模式的主要优点在于增强控制、提高灵活性和优化资源使用,但也可能增加系统的复杂性。常见应用场景包括虚拟代理、保护代理、远程代理和智能代理。

在Java中,java.lang.reflect.Proxy 和 java.io.BufferedInputStream 是代理模式的典型应用,展示了其在实际开发中的重要作用。通过合理运用代理模式,开发者可以有效地管理对象访问,提升系统的可维护性和性能。

用户评论