代理模式:远程、虚拟与保护代理
代理模式:远程、虚拟与保护代理
代理模式概述
代理模式为其他对象提供一种代理以控制对这个对象的访问。代理模式有多种变体:远程代理为远程对象提供本地代表,虚拟代理延迟对象的创建和加载,保护代理控制对象的访问权限。
// 服务接口
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框架,虚拟代理用于延迟加载和缓存,保护代理实现权限控制。结合装饰器模式可以在代理层添加日志、监控、限流等横切功能。