6.1 外观模式(Facade Pattern)

6.1.1 模式定义与动机

定义: 外观模式为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

动机: - 子系统越来越复杂,需要简化客户端的使用 - 减少客户端与子系统之间的依赖关系 - 为复杂的子系统提供简单的接口 - 实现子系统的分层

6.1.2 模式结构

┌─────────────┐    ┌─────────────┐
│   Client    │───▶│   Facade    │
│             │    │             │
└─────────────┘    └─────────────┘
                           │
                           ▼
                   ┌─────────────┐
                   │ Subsystem   │
                   │ Classes     │
                   │ A, B, C...  │
                   └─────────────┘

角色说明: - Facade(外观): 知道哪些子系统类负责处理请求,将客户的请求代理给适当的子系统对象 - Subsystem Classes(子系统类): 实现子系统的功能,处理由Facade对象指派的任务 - Client(客户端): 通过Facade接口与子系统通信

6.1.3 Python实现示例

# Python外观模式实现 - 智能家居系统
from abc import ABC, abstractmethod
from typing import Dict, List, Any
from enum import Enum
import time
from datetime import datetime

# 子系统1:照明系统
class LightingSystem:
    """照明子系统"""
    
    def __init__(self):
        self._lights = {
            'living_room': {'brightness': 0, 'color': 'white', 'on': False},
            'bedroom': {'brightness': 0, 'color': 'white', 'on': False},
            'kitchen': {'brightness': 0, 'color': 'white', 'on': False},
            'bathroom': {'brightness': 0, 'color': 'white', 'on': False}
        }
    
    def turn_on_light(self, room: str, brightness: int = 100, color: str = 'white'):
        """开启指定房间的灯光"""
        if room in self._lights:
            self._lights[room] = {
                'brightness': brightness,
                'color': color,
                'on': True
            }
            print(f"[LightingSystem] {room} light turned ON - Brightness: {brightness}%, Color: {color}")
        else:
            print(f"[LightingSystem] Room '{room}' not found")
    
    def turn_off_light(self, room: str):
        """关闭指定房间的灯光"""
        if room in self._lights:
            self._lights[room]['on'] = False
            self._lights[room]['brightness'] = 0
            print(f"[LightingSystem] {room} light turned OFF")
        else:
            print(f"[LightingSystem] Room '{room}' not found")
    
    def dim_light(self, room: str, brightness: int):
        """调节灯光亮度"""
        if room in self._lights and self._lights[room]['on']:
            self._lights[room]['brightness'] = max(0, min(100, brightness))
            print(f"[LightingSystem] {room} light dimmed to {brightness}%")
        else:
            print(f"[LightingSystem] Cannot dim light in '{room}' - light is off or room not found")
    
    def turn_on_all_lights(self, brightness: int = 80):
        """开启所有灯光"""
        for room in self._lights:
            self.turn_on_light(room, brightness)
    
    def turn_off_all_lights(self):
        """关闭所有灯光"""
        for room in self._lights:
            self.turn_off_light(room)
    
    def get_status(self) -> Dict[str, Any]:
        """获取照明系统状态"""
        return self._lights.copy()

# 子系统2:安全系统
class SecuritySystem:
    """安全子系统"""
    
    def __init__(self):
        self._armed = False
        self._alarm_triggered = False
        self._sensors = {
            'door': {'active': True, 'triggered': False},
            'window': {'active': True, 'triggered': False},
            'motion': {'active': True, 'triggered': False},
            'smoke': {'active': True, 'triggered': False}
        }
        self._access_code = "1234"
    
    def arm_system(self, code: str):
        """布防安全系统"""
        if code == self._access_code:
            self._armed = True
            self._alarm_triggered = False
            print("[SecuritySystem] Security system ARMED")
            return True
        else:
            print("[SecuritySystem] Invalid access code - cannot arm system")
            return False
    
    def disarm_system(self, code: str):
        """撤防安全系统"""
        if code == self._access_code:
            self._armed = False
            self._alarm_triggered = False
            print("[SecuritySystem] Security system DISARMED")
            return True
        else:
            print("[SecuritySystem] Invalid access code - cannot disarm system")
            return False
    
    def trigger_alarm(self, sensor_type: str):
        """触发警报"""
        if self._armed and sensor_type in self._sensors:
            self._alarm_triggered = True
            self._sensors[sensor_type]['triggered'] = True
            print(f"[SecuritySystem] ALARM TRIGGERED by {sensor_type} sensor!")
    
    def reset_alarm(self, code: str):
        """重置警报"""
        if code == self._access_code:
            self._alarm_triggered = False
            for sensor in self._sensors.values():
                sensor['triggered'] = False
            print("[SecuritySystem] Alarm reset")
            return True
        else:
            print("[SecuritySystem] Invalid access code - cannot reset alarm")
            return False
    
    def get_status(self) -> Dict[str, Any]:
        """获取安全系统状态"""
        return {
            'armed': self._armed,
            'alarm_triggered': self._alarm_triggered,
            'sensors': self._sensors.copy()
        }

# 子系统3:气候控制系统
class ClimateControlSystem:
    """气候控制子系统"""
    
    def __init__(self):
        self._temperature = 22  # 摄氏度
        self._humidity = 50     # 百分比
        self._ac_on = False
        self._heater_on = False
        self._fan_speed = 0     # 0-5级
        self._target_temperature = 22
    
    def set_temperature(self, temperature: int):
        """设置目标温度"""
        self._target_temperature = max(16, min(30, temperature))
        self._adjust_climate()
        print(f"[ClimateControl] Target temperature set to {self._target_temperature}°C")
    
    def turn_on_ac(self, temperature: int = 24):
        """开启空调"""
        self._ac_on = True
        self._heater_on = False
        self._target_temperature = temperature
        self._fan_speed = 3
        print(f"[ClimateControl] Air conditioning turned ON - Target: {temperature}°C")
    
    def turn_on_heater(self, temperature: int = 22):
        """开启暖气"""
        self._heater_on = True
        self._ac_on = False
        self._target_temperature = temperature
        self._fan_speed = 2
        print(f"[ClimateControl] Heater turned ON - Target: {temperature}°C")
    
    def turn_off_climate_control(self):
        """关闭气候控制"""
        self._ac_on = False
        self._heater_on = False
        self._fan_speed = 0
        print("[ClimateControl] Climate control turned OFF")
    
    def set_fan_speed(self, speed: int):
        """设置风扇速度"""
        self._fan_speed = max(0, min(5, speed))
        print(f"[ClimateControl] Fan speed set to {self._fan_speed}")
    
    def _adjust_climate(self):
        """自动调节气候"""
        if self._target_temperature > self._temperature:
            if not self._heater_on:
                self.turn_on_heater(self._target_temperature)
        elif self._target_temperature < self._temperature:
            if not self._ac_on:
                self.turn_on_ac(self._target_temperature)
    
    def get_status(self) -> Dict[str, Any]:
        """获取气候控制状态"""
        return {
            'current_temperature': self._temperature,
            'target_temperature': self._target_temperature,
            'humidity': self._humidity,
            'ac_on': self._ac_on,
            'heater_on': self._heater_on,
            'fan_speed': self._fan_speed
        }

# 子系统4:娱乐系统
class EntertainmentSystem:
    """娱乐子系统"""
    
    def __init__(self):
        self._tv_on = False
        self._tv_channel = 1
        self._tv_volume = 20
        self._sound_system_on = False
        self._sound_volume = 30
        self._music_playing = False
        self._current_song = None
    
    def turn_on_tv(self, channel: int = 1, volume: int = 20):
        """开启电视"""
        self._tv_on = True
        self._tv_channel = channel
        self._tv_volume = volume
        print(f"[Entertainment] TV turned ON - Channel: {channel}, Volume: {volume}")
    
    def turn_off_tv(self):
        """关闭电视"""
        self._tv_on = False
        print("[Entertainment] TV turned OFF")
    
    def change_channel(self, channel: int):
        """换台"""
        if self._tv_on:
            self._tv_channel = channel
            print(f"[Entertainment] TV channel changed to {channel}")
        else:
            print("[Entertainment] Cannot change channel - TV is off")
    
    def set_tv_volume(self, volume: int):
        """设置电视音量"""
        if self._tv_on:
            self._tv_volume = max(0, min(100, volume))
            print(f"[Entertainment] TV volume set to {self._tv_volume}")
    
    def turn_on_sound_system(self, volume: int = 30):
        """开启音响系统"""
        self._sound_system_on = True
        self._sound_volume = volume
        print(f"[Entertainment] Sound system turned ON - Volume: {volume}")
    
    def turn_off_sound_system(self):
        """关闭音响系统"""
        self._sound_system_on = False
        self._music_playing = False
        print("[Entertainment] Sound system turned OFF")
    
    def play_music(self, song: str = "Default Playlist"):
        """播放音乐"""
        if self._sound_system_on:
            self._music_playing = True
            self._current_song = song
            print(f"[Entertainment] Playing music: {song}")
        else:
            print("[Entertainment] Cannot play music - sound system is off")
    
    def stop_music(self):
        """停止音乐"""
        self._music_playing = False
        self._current_song = None
        print("[Entertainment] Music stopped")
    
    def get_status(self) -> Dict[str, Any]:
        """获取娱乐系统状态"""
        return {
            'tv_on': self._tv_on,
            'tv_channel': self._tv_channel,
            'tv_volume': self._tv_volume,
            'sound_system_on': self._sound_system_on,
            'sound_volume': self._sound_volume,
            'music_playing': self._music_playing,
            'current_song': self._current_song
        }

# 外观类:智能家居控制器
class SmartHomeFacade:
    """智能家居外观类"""
    
    def __init__(self):
        # 初始化所有子系统
        self._lighting = LightingSystem()
        self._security = SecuritySystem()
        self._climate = ClimateControlSystem()
        self._entertainment = EntertainmentSystem()
        
        # 预定义场景
        self._scenes = {
            'morning': self._morning_scene,
            'evening': self._evening_scene,
            'night': self._night_scene,
            'away': self._away_scene,
            'party': self._party_scene,
            'movie': self._movie_scene
        }
    
    # 高级场景控制方法
    def activate_scene(self, scene_name: str, **kwargs):
        """激活预定义场景"""
        if scene_name in self._scenes:
            print(f"\n=== Activating {scene_name.upper()} Scene ===")
            self._scenes[scene_name](**kwargs)
            print(f"=== {scene_name.upper()} Scene Activated ===\n")
        else:
            print(f"Unknown scene: {scene_name}")
            print(f"Available scenes: {list(self._scenes.keys())}")
    
    def _morning_scene(self, **kwargs):
        """晨起场景"""
        # 逐渐开启灯光
        self._lighting.turn_on_light('bedroom', 30, 'warm_white')
        self._lighting.turn_on_light('bathroom', 80, 'white')
        self._lighting.turn_on_light('kitchen', 90, 'white')
        
        # 设置舒适温度
        self._climate.set_temperature(23)
        
        # 播放轻音乐
        self._entertainment.turn_on_sound_system(20)
        self._entertainment.play_music("Morning Playlist")
        
        # 撤防安全系统
        code = kwargs.get('security_code', '1234')
        self._security.disarm_system(code)
    
    def _evening_scene(self, **kwargs):
        """傍晚场景"""
        # 开启温馨灯光
        self._lighting.turn_on_light('living_room', 60, 'warm_white')
        self._lighting.turn_on_light('kitchen', 70, 'white')
        self._lighting.turn_on_light('bedroom', 40, 'warm_white')
        
        # 调节温度
        self._climate.set_temperature(22)
        
        # 开启电视
        self._entertainment.turn_on_tv(5, 25)
    
    def _night_scene(self, **kwargs):
        """夜间场景"""
        # 关闭大部分灯光,保留夜灯
        self._lighting.turn_off_all_lights()
        self._lighting.turn_on_light('bedroom', 10, 'blue')
        self._lighting.turn_on_light('bathroom', 20, 'warm_white')
        
        # 降低温度
        self._climate.set_temperature(20)
        
        # 关闭娱乐设备
        self._entertainment.turn_off_tv()
        self._entertainment.turn_off_sound_system()
        
        # 布防安全系统
        code = kwargs.get('security_code', '1234')
        self._security.arm_system(code)
    
    def _away_scene(self, **kwargs):
        """离家场景"""
        # 关闭所有灯光
        self._lighting.turn_off_all_lights()
        
        # 关闭气候控制
        self._climate.turn_off_climate_control()
        
        # 关闭所有娱乐设备
        self._entertainment.turn_off_tv()
        self._entertainment.turn_off_sound_system()
        
        # 布防安全系统
        code = kwargs.get('security_code', '1234')
        self._security.arm_system(code)
    
    def _party_scene(self, **kwargs):
        """聚会场景"""
        # 开启彩色灯光
        self._lighting.turn_on_light('living_room', 100, 'rainbow')
        self._lighting.turn_on_light('kitchen', 80, 'white')
        
        # 设置舒适温度
        self._climate.set_temperature(21)
        
        # 开启音响系统
        self._entertainment.turn_on_sound_system(60)
        self._entertainment.play_music("Party Playlist")
        
        # 撤防安全系统(客人进出)
        code = kwargs.get('security_code', '1234')
        self._security.disarm_system(code)
    
    def _movie_scene(self, **kwargs):
        """观影场景"""
        # 调暗灯光
        self._lighting.turn_off_all_lights()
        self._lighting.turn_on_light('living_room', 20, 'blue')
        
        # 设置舒适温度
        self._climate.set_temperature(22)
        
        # 开启电视和音响
        self._entertainment.turn_on_tv(kwargs.get('channel', 10), 30)
        self._entertainment.turn_on_sound_system(50)
    
    # 简化的控制方法
    def good_morning(self, security_code: str = '1234'):
        """早安模式"""
        self.activate_scene('morning', security_code=security_code)
    
    def good_night(self, security_code: str = '1234'):
        """晚安模式"""
        self.activate_scene('night', security_code=security_code)
    
    def leaving_home(self, security_code: str = '1234'):
        """离家模式"""
        self.activate_scene('away', security_code=security_code)
    
    def coming_home(self, security_code: str = '1234'):
        """回家模式"""
        self.activate_scene('evening', security_code=security_code)
    
    def start_party(self, security_code: str = '1234'):
        """聚会模式"""
        self.activate_scene('party', security_code=security_code)
    
    def watch_movie(self, channel: int = 10, security_code: str = '1234'):
        """观影模式"""
        self.activate_scene('movie', channel=channel, security_code=security_code)
    
    # 紧急控制方法
    def emergency_shutdown(self):
        """紧急关闭所有系统"""
        print("\n!!! EMERGENCY SHUTDOWN !!!")
        self._lighting.turn_off_all_lights()
        self._climate.turn_off_climate_control()
        self._entertainment.turn_off_tv()
        self._entertainment.turn_off_sound_system()
        print("All systems shut down for safety")
    
    def security_alert(self, sensor_type: str = 'motion'):
        """安全警报"""
        print("\n!!! SECURITY ALERT !!!")
        self._security.trigger_alarm(sensor_type)
        # 开启所有灯光
        self._lighting.turn_on_all_lights(100)
        # 关闭娱乐系统
        self._entertainment.turn_off_tv()
        self._entertainment.turn_off_sound_system()
    
    # 状态查询方法
    def get_system_status(self) -> Dict[str, Any]:
        """获取整个系统状态"""
        return {
            'timestamp': datetime.now().isoformat(),
            'lighting': self._lighting.get_status(),
            'security': self._security.get_status(),
            'climate': self._climate.get_status(),
            'entertainment': self._entertainment.get_status()
        }
    
    def get_available_scenes(self) -> List[str]:
        """获取可用场景列表"""
        return list(self._scenes.keys())
    
    # 直接访问子系统的方法(可选)
    def get_lighting_system(self) -> LightingSystem:
        """获取照明系统(用于高级控制)"""
        return self._lighting
    
    def get_security_system(self) -> SecuritySystem:
        """获取安全系统(用于高级控制)"""
        return self._security
    
    def get_climate_system(self) -> ClimateControlSystem:
        """获取气候系统(用于高级控制)"""
        return self._climate
    
    def get_entertainment_system(self) -> EntertainmentSystem:
        """获取娱乐系统(用于高级控制)"""
        return self._entertainment

# 使用示例和演示
def demonstrate_facade_pattern():
    print("=== Facade Pattern Demo - Smart Home System ===")
    print()
    
    # 创建智能家居控制器
    smart_home = SmartHomeFacade()
    
    print(f"Available scenes: {smart_home.get_available_scenes()}")
    print()
    
    # 演示1:早晨场景
    print("1. Morning Routine:")
    smart_home.good_morning()
    
    # 演示2:查看系统状态
    print("2. System Status Check:")
    status = smart_home.get_system_status()
    print(f"Lighting status: {len([room for room, info in status['lighting'].items() if info['on']])} rooms lit")
    print(f"Security armed: {status['security']['armed']}")
    print(f"Climate target: {status['climate']['target_temperature']}°C")
    print(f"Entertainment: TV={status['entertainment']['tv_on']}, Music={status['entertainment']['music_playing']}")
    print()
    
    # 演示3:观影模式
    print("3. Movie Night:")
    smart_home.watch_movie(channel=15)
    
    # 演示4:聚会模式
    print("4. Party Time:")
    smart_home.start_party()
    
    # 演示5:离家模式
    print("5. Leaving Home:")
    smart_home.leaving_home()
    
    # 演示6:安全警报
    print("6. Security Alert Simulation:")
    smart_home.security_alert('door')
    
    # 演示7:紧急关闭
    print("7. Emergency Shutdown:")
    smart_home.emergency_shutdown()
    
    # 演示8:高级控制(直接访问子系统)
    print("8. Advanced Control (Direct Subsystem Access):")
    lighting = smart_home.get_lighting_system()
    lighting.turn_on_light('living_room', 50, 'purple')
    
    climate = smart_home.get_climate_system()
    climate.set_fan_speed(4)
    
    print("\n" + "="*60)
    print("Facade Pattern Benefits Demonstrated:")
    print("1. Simplified interface for complex subsystems")
    print("2. Reduced coupling between client and subsystems")
    print("3. Layered architecture with high-level operations")
    print("4. Easy-to-use predefined scenarios")
    print("5. Optional direct access to subsystems for advanced users")

if __name__ == "__main__":
    demonstrate_facade_pattern()

6.1.4 外观模式的优缺点

优点: 1. 简化接口: 为复杂子系统提供简单接口 2. 降低耦合: 减少客户端与子系统的依赖 3. 分层设计: 支持系统的分层架构 4. 易于使用: 客户端无需了解子系统的复杂性

缺点: 1. 功能限制: 可能无法提供子系统的所有功能 2. 违反开闭原则: 增加新的子系统可能需要修改外观类 3. 性能开销: 增加了一层间接调用

6.1.5 适用场景

  1. 复杂子系统简化: 当子系统很复杂时
  2. 分层架构: 构建分层系统时的层间接口
  3. 遗留系统集成: 为老系统提供现代化接口
  4. API设计: 为复杂的API提供简化版本

6.2 代理模式(Proxy Pattern)

6.2.1 模式定义与动机

定义: 代理模式为其他对象提供一种代理以控制对这个对象的访问。

动机: - 控制对象的访问权限 - 延迟对象的创建和初始化 - 在访问对象时执行额外的操作 - 为远程对象提供本地代表

6.2.2 代理模式的类型

  1. 虚拟代理(Virtual Proxy): 延迟创建开销大的对象
  2. 保护代理(Protection Proxy): 控制对原始对象的访问权限
  3. 远程代理(Remote Proxy): 为远程对象提供本地代理
  4. 缓存代理(Cache Proxy): 为开销大的运算结果提供缓存
  5. 智能引用代理(Smart Reference Proxy): 提供额外的服务

6.2.3 模式结构

┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   Client    │───▶│   Subject   │◀───│ RealSubject │
│             │    │ (interface) │    │             │
└─────────────┘    └─────────────┘    └─────────────┘
                           ▲
                           │
                   ┌─────────────┐
                   │    Proxy    │
                   │             │
                   └─────────────┘

6.2.4 Python实现示例

# Python代理模式实现 - 图像加载系统
from abc import ABC, abstractmethod
from typing import Dict, Any, Optional, List
import time
import hashlib
from datetime import datetime, timedelta
from enum import Enum

# 权限枚举
class Permission(Enum):
    READ = "read"
    WRITE = "write"
    DELETE = "delete"
    ADMIN = "admin"

# 用户类
class User:
    """用户类"""
    
    def __init__(self, username: str, permissions: List[Permission]):
        self.username = username
        self.permissions = permissions
        self.login_time = datetime.now()
    
    def has_permission(self, permission: Permission) -> bool:
        return permission in self.permissions or Permission.ADMIN in self.permissions

# 抽象主题接口
class ImageService(ABC):
    """图像服务接口"""
    
    @abstractmethod
    def load_image(self, image_path: str) -> Dict[str, Any]:
        """加载图像"""
        pass
    
    @abstractmethod
    def save_image(self, image_path: str, image_data: bytes) -> bool:
        """保存图像"""
        pass
    
    @abstractmethod
    def delete_image(self, image_path: str) -> bool:
        """删除图像"""
        pass
    
    @abstractmethod
    def get_image_info(self, image_path: str) -> Dict[str, Any]:
        """获取图像信息"""
        pass

# 真实主题:实际的图像服务
class RealImageService(ImageService):
    """真实的图像服务实现"""
    
    def __init__(self):
        self._images = {}  # 模拟图像存储
        self._load_count = 0
        self._save_count = 0
        self._delete_count = 0
    
    def load_image(self, image_path: str) -> Dict[str, Any]:
        """加载图像(模拟耗时操作)"""
        print(f"[RealImageService] Loading image: {image_path}")
        
        # 模拟图像加载的耗时操作
        time.sleep(0.5)  # 模拟I/O延迟
        
        self._load_count += 1
        
        if image_path in self._images:
            image_data = self._images[image_path]
            return {
                'status': 'success',
                'path': image_path,
                'size': image_data['size'],
                'format': image_data['format'],
                'data': image_data['data'],
                'loaded_at': datetime.now().isoformat(),
                'load_time': 0.5
            }
        else:
            return {
                'status': 'not_found',
                'path': image_path,
                'error': 'Image not found'
            }
    
    def save_image(self, image_path: str, image_data: bytes) -> bool:
        """保存图像"""
        print(f"[RealImageService] Saving image: {image_path}")
        
        # 模拟图像保存操作
        time.sleep(0.2)
        
        self._save_count += 1
        
        # 模拟图像元数据
        self._images[image_path] = {
            'data': image_data,
            'size': len(image_data),
            'format': self._detect_format(image_path),
            'created_at': datetime.now().isoformat(),
            'modified_at': datetime.now().isoformat()
        }
        
        return True
    
    def delete_image(self, image_path: str) -> bool:
        """删除图像"""
        print(f"[RealImageService] Deleting image: {image_path}")
        
        self._delete_count += 1
        
        if image_path in self._images:
            del self._images[image_path]
            return True
        else:
            return False
    
    def get_image_info(self, image_path: str) -> Dict[str, Any]:
        """获取图像信息"""
        if image_path in self._images:
            return self._images[image_path].copy()
        else:
            return {'error': 'Image not found'}
    
    def _detect_format(self, image_path: str) -> str:
        """检测图像格式"""
        if image_path.lower().endswith('.jpg') or image_path.lower().endswith('.jpeg'):
            return 'JPEG'
        elif image_path.lower().endswith('.png'):
            return 'PNG'
        elif image_path.lower().endswith('.gif'):
            return 'GIF'
        else:
            return 'UNKNOWN'
    
    def get_statistics(self) -> Dict[str, int]:
        """获取服务统计信息"""
        return {
            'load_count': self._load_count,
            'save_count': self._save_count,
            'delete_count': self._delete_count,
            'total_images': len(self._images)
        }

# 虚拟代理:延迟加载
class VirtualImageProxy(ImageService):
    """虚拟代理 - 延迟加载图像服务"""
    
    def __init__(self):
        self._real_service: Optional[RealImageService] = None
        self._initialized = False
    
    def _get_real_service(self) -> RealImageService:
        """延迟初始化真实服务"""
        if self._real_service is None:
            print("[VirtualProxy] Initializing real image service...")
            self._real_service = RealImageService()
            self._initialized = True
        return self._real_service
    
    def load_image(self, image_path: str) -> Dict[str, Any]:
        print(f"[VirtualProxy] Request to load image: {image_path}")
        real_service = self._get_real_service()
        return real_service.load_image(image_path)
    
    def save_image(self, image_path: str, image_data: bytes) -> bool:
        print(f"[VirtualProxy] Request to save image: {image_path}")
        real_service = self._get_real_service()
        return real_service.save_image(image_path, image_data)
    
    def delete_image(self, image_path: str) -> bool:
        print(f"[VirtualProxy] Request to delete image: {image_path}")
        real_service = self._get_real_service()
        return real_service.delete_image(image_path)
    
    def get_image_info(self, image_path: str) -> Dict[str, Any]:
        print(f"[VirtualProxy] Request for image info: {image_path}")
        real_service = self._get_real_service()
        return real_service.get_image_info(image_path)
    
    def is_initialized(self) -> bool:
        """检查是否已初始化"""
        return self._initialized

# 保护代理:权限控制
class ProtectionImageProxy(ImageService):
    """保护代理 - 权限控制"""
    
    def __init__(self, real_service: ImageService, current_user: User):
        self._real_service = real_service
        self._current_user = current_user
        self._access_log = []
    
    def load_image(self, image_path: str) -> Dict[str, Any]:
        if self._check_permission(Permission.READ, 'load_image', image_path):
            return self._real_service.load_image(image_path)
        else:
            return {
                'status': 'access_denied',
                'error': 'Insufficient permissions to load image'
            }
    
    def save_image(self, image_path: str, image_data: bytes) -> bool:
        if self._check_permission(Permission.WRITE, 'save_image', image_path):
            return self._real_service.save_image(image_path, image_data)
        else:
            print(f"[ProtectionProxy] Access denied: {self._current_user.username} cannot save images")
            return False
    
    def delete_image(self, image_path: str) -> bool:
        if self._check_permission(Permission.DELETE, 'delete_image', image_path):
            return self._real_service.delete_image(image_path)
        else:
            print(f"[ProtectionProxy] Access denied: {self._current_user.username} cannot delete images")
            return False
    
    def get_image_info(self, image_path: str) -> Dict[str, Any]:
        if self._check_permission(Permission.READ, 'get_image_info', image_path):
            return self._real_service.get_image_info(image_path)
        else:
            return {
                'error': 'Insufficient permissions to access image info'
            }
    
    def _check_permission(self, required_permission: Permission, operation: str, resource: str) -> bool:
        """检查权限"""
        has_permission = self._current_user.has_permission(required_permission)
        
        # 记录访问日志
        self._access_log.append({
            'timestamp': datetime.now().isoformat(),
            'user': self._current_user.username,
            'operation': operation,
            'resource': resource,
            'permission_required': required_permission.value,
            'access_granted': has_permission
        })
        
        if has_permission:
            print(f"[ProtectionProxy] Access granted: {self._current_user.username} -> {operation}")
        else:
            print(f"[ProtectionProxy] Access denied: {self._current_user.username} -> {operation} (requires {required_permission.value})")
        
        return has_permission
    
    def get_access_log(self) -> List[Dict[str, Any]]:
        """获取访问日志"""
        return self._access_log.copy()

# 缓存代理:结果缓存
class CacheImageProxy(ImageService):
    """缓存代理 - 缓存图像加载结果"""
    
    def __init__(self, real_service: ImageService, cache_ttl: int = 300):
        self._real_service = real_service
        self._cache = {}
        self._cache_ttl = cache_ttl  # 缓存生存时间(秒)
        self._cache_hits = 0
        self._cache_misses = 0
    
    def load_image(self, image_path: str) -> Dict[str, Any]:
        cache_key = self._generate_cache_key('load', image_path)
        
        # 检查缓存
        cached_result = self._get_from_cache(cache_key)
        if cached_result is not None:
            print(f"[CacheProxy] Cache hit for image: {image_path}")
            self._cache_hits += 1
            cached_result['cache_hit'] = True
            return cached_result
        
        print(f"[CacheProxy] Cache miss for image: {image_path}")
        self._cache_misses += 1
        
        # 缓存未命中,调用真实服务
        result = self._real_service.load_image(image_path)
        result['cache_hit'] = False
        
        # 只缓存成功的结果
        if result.get('status') == 'success':
            self._add_to_cache(cache_key, result)
        
        return result
    
    def save_image(self, image_path: str, image_data: bytes) -> bool:
        # 保存操作会使相关缓存失效
        self._invalidate_cache_for_image(image_path)
        return self._real_service.save_image(image_path, image_data)
    
    def delete_image(self, image_path: str) -> bool:
        # 删除操作会使相关缓存失效
        self._invalidate_cache_for_image(image_path)
        return self._real_service.delete_image(image_path)
    
    def get_image_info(self, image_path: str) -> Dict[str, Any]:
        cache_key = self._generate_cache_key('info', image_path)
        
        # 检查缓存
        cached_result = self._get_from_cache(cache_key)
        if cached_result is not None:
            print(f"[CacheProxy] Cache hit for image info: {image_path}")
            self._cache_hits += 1
            return cached_result
        
        print(f"[CacheProxy] Cache miss for image info: {image_path}")
        self._cache_misses += 1
        
        # 缓存未命中,调用真实服务
        result = self._real_service.get_image_info(image_path)
        
        # 只缓存成功的结果
        if 'error' not in result:
            self._add_to_cache(cache_key, result)
        
        return result
    
    def _generate_cache_key(self, operation: str, image_path: str) -> str:
        """生成缓存键"""
        key_string = f"{operation}:{image_path}"
        return hashlib.md5(key_string.encode()).hexdigest()
    
    def _get_from_cache(self, cache_key: str) -> Optional[Dict[str, Any]]:
        """从缓存获取数据"""
        if cache_key in self._cache:
            cache_entry = self._cache[cache_key]
            if time.time() - cache_entry['timestamp'] < self._cache_ttl:
                return cache_entry['data'].copy()
            else:
                # 缓存过期,删除
                del self._cache[cache_key]
        return None
    
    def _add_to_cache(self, cache_key: str, data: Dict[str, Any]):
        """添加到缓存"""
        self._cache[cache_key] = {
            'data': data.copy(),
            'timestamp': time.time()
        }
    
    def _invalidate_cache_for_image(self, image_path: str):
        """使指定图像的缓存失效"""
        keys_to_remove = []
        for cache_key, cache_entry in self._cache.items():
            # 检查缓存键是否与图像路径相关
            if image_path in cache_key:
                keys_to_remove.append(cache_key)
        
        for key in keys_to_remove:
            del self._cache[key]
            print(f"[CacheProxy] Invalidated cache for key: {key}")
    
    def get_cache_statistics(self) -> Dict[str, Any]:
        """获取缓存统计信息"""
        total_requests = self._cache_hits + self._cache_misses
        hit_rate = (self._cache_hits / total_requests * 100) if total_requests > 0 else 0
        
        return {
            'cache_hits': self._cache_hits,
            'cache_misses': self._cache_misses,
            'hit_rate': f"{hit_rate:.2f}%",
            'cache_size': len(self._cache),
            'cache_ttl': self._cache_ttl
        }

# 智能引用代理:额外服务
class SmartReferenceProxy(ImageService):
    """智能引用代理 - 提供额外的服务和统计"""
    
    def __init__(self, real_service: ImageService):
        self._real_service = real_service
        self._reference_count = {}
        self._operation_history = []
        self._performance_metrics = {
            'total_operations': 0,
            'total_time': 0.0,
            'average_time': 0.0
        }
    
    def load_image(self, image_path: str) -> Dict[str, Any]:
        return self._execute_with_tracking('load_image', image_path, 
                                         lambda: self._real_service.load_image(image_path))
    
    def save_image(self, image_path: str, image_data: bytes) -> bool:
        return self._execute_with_tracking('save_image', image_path,
                                         lambda: self._real_service.save_image(image_path, image_data))
    
    def delete_image(self, image_path: str) -> bool:
        result = self._execute_with_tracking('delete_image', image_path,
                                           lambda: self._real_service.delete_image(image_path))
        # 删除引用计数
        if result and image_path in self._reference_count:
            del self._reference_count[image_path]
        return result
    
    def get_image_info(self, image_path: str) -> Dict[str, Any]:
        return self._execute_with_tracking('get_image_info', image_path,
                                         lambda: self._real_service.get_image_info(image_path))
    
    def _execute_with_tracking(self, operation: str, image_path: str, func):
        """执行操作并跟踪统计信息"""
        start_time = time.time()
        
        # 更新引用计数
        if image_path not in self._reference_count:
            self._reference_count[image_path] = 0
        self._reference_count[image_path] += 1
        
        try:
            result = func()
            execution_time = time.time() - start_time
            
            # 记录操作历史
            self._operation_history.append({
                'timestamp': datetime.now().isoformat(),
                'operation': operation,
                'image_path': image_path,
                'execution_time': execution_time,
                'success': True
            })
            
            # 更新性能指标
            self._update_performance_metrics(execution_time)
            
            print(f"[SmartProxy] {operation} completed in {execution_time:.3f}s")
            
            return result
            
        except Exception as e:
            execution_time = time.time() - start_time
            
            # 记录失败的操作
            self._operation_history.append({
                'timestamp': datetime.now().isoformat(),
                'operation': operation,
                'image_path': image_path,
                'execution_time': execution_time,
                'success': False,
                'error': str(e)
            })
            
            print(f"[SmartProxy] {operation} failed after {execution_time:.3f}s: {str(e)}")
            raise
    
    def _update_performance_metrics(self, execution_time: float):
        """更新性能指标"""
        self._performance_metrics['total_operations'] += 1
        self._performance_metrics['total_time'] += execution_time
        self._performance_metrics['average_time'] = (
            self._performance_metrics['total_time'] / self._performance_metrics['total_operations']
        )
    
    def get_reference_count(self, image_path: str) -> int:
        """获取图像的引用计数"""
        return self._reference_count.get(image_path, 0)
    
    def get_all_reference_counts(self) -> Dict[str, int]:
        """获取所有图像的引用计数"""
        return self._reference_count.copy()
    
    def get_operation_history(self, limit: int = 10) -> List[Dict[str, Any]]:
        """获取操作历史"""
        return self._operation_history[-limit:]
    
    def get_performance_metrics(self) -> Dict[str, Any]:
        """获取性能指标"""
        return self._performance_metrics.copy()
    
    def get_most_accessed_images(self, top_n: int = 5) -> List[tuple]:
        """获取访问次数最多的图像"""
        sorted_images = sorted(self._reference_count.items(), 
                             key=lambda x: x[1], reverse=True)
        return sorted_images[:top_n]

# 使用示例和演示
def demonstrate_proxy_pattern():
    print("=== Proxy Pattern Demo ===")
    print()
    
    # 创建用户
    admin_user = User("admin", [Permission.ADMIN])
    read_user = User("reader", [Permission.READ])
    write_user = User("writer", [Permission.READ, Permission.WRITE])
    
    print("1. Virtual Proxy Demo (Lazy Initialization):")
    print("-" * 50)
    
    # 虚拟代理演示
    virtual_proxy = VirtualImageProxy()
    print(f"Proxy initialized: {virtual_proxy.is_initialized()}")
    
    # 第一次访问会触发真实服务的初始化
    virtual_proxy.save_image("test1.jpg", b"fake_image_data_1")
    print(f"Proxy initialized after first use: {virtual_proxy.is_initialized()}")
    print()
    
    print("2. Protection Proxy Demo (Access Control):")
    print("-" * 50)
    
    # 创建真实服务并添加一些测试数据
    real_service = RealImageService()
    real_service.save_image("public.jpg", b"public_image_data")
    real_service.save_image("private.jpg", b"private_image_data")
    
    # 保护代理演示 - 只读用户
    protection_proxy_read = ProtectionImageProxy(real_service, read_user)
    
    print("Testing with read-only user:")
    result = protection_proxy_read.load_image("public.jpg")
    print(f"Load result: {result.get('status')}")
    
    success = protection_proxy_read.save_image("new.jpg", b"new_data")
    print(f"Save result: {success}")
    
    success = protection_proxy_read.delete_image("public.jpg")
    print(f"Delete result: {success}")
    
    print("\nTesting with write user:")
    protection_proxy_write = ProtectionImageProxy(real_service, write_user)
    success = protection_proxy_write.save_image("new.jpg", b"new_data")
    print(f"Save result: {success}")
    
    print("\nAccess log:")
    for log_entry in protection_proxy_read.get_access_log()[-3:]:
        print(f"  {log_entry['operation']}: {log_entry['access_granted']}")
    print()
    
    print("3. Cache Proxy Demo (Result Caching):")
    print("-" * 50)
    
    # 缓存代理演示
    cache_proxy = CacheImageProxy(real_service, cache_ttl=60)
    
    # 第一次加载(缓存未命中)
    print("First load (cache miss):")
    result1 = cache_proxy.load_image("public.jpg")
    print(f"Cache hit: {result1.get('cache_hit')}")
    
    # 第二次加载(缓存命中)
    print("\nSecond load (cache hit):")
    result2 = cache_proxy.load_image("public.jpg")
    print(f"Cache hit: {result2.get('cache_hit')}")
    
    print(f"\nCache statistics: {cache_proxy.get_cache_statistics()}")
    print()
    
    print("4. Smart Reference Proxy Demo (Additional Services):")
    print("-" * 50)
    
    # 智能引用代理演示
    smart_proxy = SmartReferenceProxy(real_service)
    
    # 执行一些操作
    smart_proxy.load_image("public.jpg")
    smart_proxy.load_image("public.jpg")  # 再次访问
    smart_proxy.load_image("private.jpg")
    smart_proxy.get_image_info("public.jpg")
    
    print(f"\nReference counts: {smart_proxy.get_all_reference_counts()}")
    print(f"Performance metrics: {smart_proxy.get_performance_metrics()}")
    print(f"Most accessed images: {smart_proxy.get_most_accessed_images()}")
    
    print("\nOperation history:")
    for operation in smart_proxy.get_operation_history(3):
        print(f"  {operation['operation']}: {operation['execution_time']:.3f}s")
    
    print("\n" + "="*60)
    print("Proxy Pattern Benefits Demonstrated:")
    print("1. Virtual Proxy: Lazy initialization of expensive objects")
    print("2. Protection Proxy: Access control and security")
    print("3. Cache Proxy: Performance optimization through caching")
    print("4. Smart Reference: Additional services and monitoring")
    print("5. Transparent interface: Client code remains unchanged")

if __name__ == "__main__":
    demonstrate_proxy_pattern()

6.2.5 代理模式的优缺点

优点: 1. 职责分离: 代理和真实对象分离关注点 2. 透明性: 客户端无需知道是否使用了代理 3. 灵活性: 可以在运行时决定是否使用代理 4. 扩展性: 可以在不修改真实对象的情况下扩展功能

缺点: 1. 复杂性增加: 增加了系统的复杂性 2. 性能开销: 增加了间接访问的开销 3. 维护成本: 需要维护代理类

6.2.6 适用场景

  1. 延迟加载: 对象创建开销大时
  2. 访问控制: 需要控制对象访问权限时
  3. 缓存: 需要缓存昂贵操作的结果时
  4. 远程访问: 访问远程对象时
  5. 引用计数: 需要跟踪对象使用情况时

6.3 外观模式与代理模式对比

特性 外观模式 代理模式
目的 简化复杂接口 控制对象访问
结构 一对多(外观对多个子系统) 一对一(代理对真实对象)
接口 提供新的简化接口 保持与真实对象相同的接口
职责 协调多个子系统 控制单个对象的访问
使用场景 子系统复杂化简 访问控制、延迟加载、缓存

6.4 本章总结

6.4.1 核心概念回顾

  1. 外观模式: 为复杂子系统提供统一的简化接口
  2. 代理模式: 为对象提供代理以控制对其的访问
  3. 结构型模式的价值: 通过组合和接口设计解决复杂性问题

6.4.2 最佳实践

  1. 外观模式最佳实践:

    • 保持外观接口简单直观
    • 允许客户端直接访问子系统(可选)
    • 避免外观类过于复杂
    • 考虑分层外观设计
  2. 代理模式最佳实践:

    • 保持代理接口与真实对象一致
    • 合理选择代理类型
    • 注意性能开销
    • 考虑代理链的组合使用

6.4.3 实际应用建议

  1. 选择合适的模式:

    • 需要简化复杂系统时选择外观模式
    • 需要控制访问或添加额外功能时选择代理模式
  2. 组合使用:

    • 可以在外观模式中使用代理模式
    • 可以为代理对象创建外观接口
  3. 性能考虑:

    • 外观模式可能增加方法调用层次
    • 代理模式要权衡额外功能与性能开销

6.4.4 注意事项

  1. 避免过度设计: 不要为了使用模式而使用模式
  2. 保持接口一致性: 特别是在代理模式中
  3. 文档化设计决策: 说明为什么选择特定的模式
  4. 测试覆盖: 确保代理和外观的所有路径都被测试

6.5 练习题

6.5.1 基础练习

  1. 外观模式练习:

    • 设计一个计算机启动外观,整合CPU、内存、硬盘等子系统
    • 实现一个在线购物外观,整合商品、订单、支付、物流等服务
  2. 代理模式练习:

    • 实现一个文件访问的保护代理,控制不同用户的文件操作权限
    • 创建一个数据库连接的虚拟代理,实现连接池管理

6.5.2 进阶练习

  1. 组合模式练习:

    • 设计一个Web服务外观,内部使用缓存代理、日志代理等
    • 实现一个分布式缓存系统,使用代理模式处理网络通信
  2. 性能优化练习:

    • 比较直接访问与使用代理的性能差异
    • 设计一个智能外观,根据负载自动选择最优的子系统

6.5.3 思考题

  1. 在什么情况下外观模式可能成为反模式?如何避免?
  2. 代理模式与装饰器模式的区别是什么?何时选择哪个?
  3. 如何设计一个既是外观又是代理的类?
  4. 在微服务架构中,外观模式和代理模式分别扮演什么角色?

下一章预告: 接下来我们将学习组合模式和享元模式,探讨如何处理树形结构和优化内存使用。