← 返回首页
🧩

代理模式:远程、虚拟与保护代理

📂 architecture ⏱ 3 min 401 words

代理模式:远程、虚拟与保护代理

代理模式概述

代理模式为其他对象提供一种代理以控制对这个对象的访问。代理模式有多种变体:远程代理为远程对象提供本地代表,虚拟代理延迟对象的创建和加载,保护代理控制对象的访问权限。

// 服务接口
public interface UserService {
    User getUserById(String id);
    List<User> searchUsers(String keyword);
    void updateUser(User user);
}

// 远程代理 - gRPC远程调用代理
public class RemoteUserProxy implements UserService {
    private final UserServiceGrpc.UserServiceBlockingStub stub;
    
    public RemoteUserProxy(String host, int port) {
        ManagedChannel channel = ManagedChannelBuilder
            .forAddress(host, port)
            .usePlaintext()
            .build();
        this.stub = UserServiceGrpc.newBlockingStub(channel);
    }
    
    @Override
    public User getUserById(String id) {
        GetUserRequest request = GetUserRequest.newBuilder().setId(id).build();
        GetUserResponse response = stub.getUserById(request);
        return convertToUser(response);
    }
    
    @Override
    public List<User> searchUsers(String keyword) {
        SearchUsersRequest request = SearchUsersRequest.newBuilder()
            .setKeyword(keyword).build();
        SearchUsersResponse response = stub.searchUsers(request);
        return response.getUsersList().stream()
            .map(this::convertToUser)
            .collect(Collectors.toList());
    }
    
    @Override
    public void updateUser(User user) {
        UpdateUserRequest request = convertToUpdateRequest(user);
        stub.updateUser(request);
    }
}

虚拟代理 - 延迟加载

虚拟代理延迟对象的创建和初始化,直到真正需要使用时才创建真实对象,节省系统资源。

// 虚拟代理 - 延迟加载图片
interface ImageLoader {
  load(): Promise<ImageData>;
  getWidth(): number;
  getHeight(): number;
}

class RealImageLoader implements ImageLoader {
  private data: ImageData | null = null;
  
  constructor(private url: string) {}
  
  async load(): Promise<ImageData> {
    if (!this.data) {
      console.log(`Loading image from ${this.url}...`);
      this.data = await fetchImage(this.url);
    }
    return this.data;
  }
  
  getWidth(): number {
    if (!this.data) throw new Error('Image not loaded');
    return this.data.width;
  }
  
  getHeight(): number {
    if (!this.data) throw new Error('Image not loaded');
    return this.data.height;
  }
}

class VirtualImageProxy implements ImageLoader {
  private realLoader: RealImageLoader | null = null;
  
  constructor(private url: string) {}
  
  async load(): Promise<ImageData> {
    if (!this.realLoader) {
      this.realLoader = new RealImageLoader(this.url);
    }
    return this.realLoader.load();
  }
  
  getWidth(): number {
    if (!this.realLoader) throw new Error('Image not loaded');
    return this.realLoader.getWidth();
  }
  
  getHeight(): number {
    if (!this.realLoader) throw new Error('Image not loaded');
    return this.realLoader.getHeight();
  }
}

// 使用虚拟代理
const images: ImageLoader[] = [
  new VirtualImageProxy('https://example.com/image1.jpg'),
  new VirtualImageProxy('https://example.com/image2.jpg'),
  new VirtualImageProxy('https://example.com/image3.jpg'),
];

// 只有实际访问时才加载
async function displayImage(index: number) {
  const imageData = await images[index].load();
  renderToScreen(imageData);
}

保护代理 - 访问控制

保护代理根据用户权限控制对真实对象的访问,实现细粒度的权限管理。

// 保护代理 - 权限控制
type ProtectedUserProxy struct {
    realService UserService
    user        *User
    permissions []string
}

func NewProtectedUserProxy(service UserService, user *User) *ProtectedUserProxy {
    return &ProtectedUserProxy{
        realService: service,
        user:        user,
        permissions: user.Permissions,
    }
}

func (p *ProtectedUserProxy) hasPermission(permission string) bool {
    for _, perm := range p.permissions {
        if perm == permission {
            return true
        }
    }
    return false
}

func (p *ProtectedUserProxy) GetUserById(id string) (*User, error) {
    if !p.hasPermission("user:read") {
        return nil, errors.New("permission denied: user:read")
    }
    return p.realService.GetUserById(id)
}

func (p *ProtectedUserProxy) SearchUsers(keyword string) ([]*User, error) {
    if !p.hasPermission("user:search") {
        return nil, errors.New("permission denied: user:search")
    }
    return p.realService.SearchUsers(keyword)
}

func (p *ProtectedUserProxy) UpdateUser(user *User) error {
    if !p.hasPermission("user:write") {
        return errors.New("permission denied: user:write")
    }
    // 只允许更新自己的信息
    if user.ID != p.user.ID && !p.hasPermission("user:admin") {
        return errors.New("permission denied: cannot update other users")
    }
    return p.realService.UpdateUser(user)
}

代理模式应用场景总结

代理模式在分布式系统中无处不在:远程代理对应RPC框架,虚拟代理用于延迟加载和缓存,保护代理实现权限控制。结合装饰器模式可以在代理层添加日志、监控、限流等横切功能。