Hello! 欢迎来到盒子萌!

python面向对象


avatar
dspirit 2025-02-02 47

[每天记录一个问题,记录十年 Blog]

面向对象:
# -*- coding: utf-8 -*-
import os
import win32gui
import win32con

# ===== 配置区域 =====
WINDOW_TITLE = "scrcpy"
APP_PACKAGE = "com.tencent.tmgp.sgamece"
APP_ACTIVITY = ".wxapi.WXEntryActivity"

# ===== 类定义 =====
class ScrcpyController:
    def __init__(self, window_title, app_package, app_activity):
        self.window_title = window_title
        self.app_package = app_package
        self.app_activity = app_activity
        self.hwnd = 0

    def find_window(self):
        """查找窗口"""
        self.hwnd = win32gui.FindWindow(None, self.window_title)
        if self.hwnd:
            print(f"找到窗口: {self.window_title}")
            return True
        print(f"未找到窗口: {self.window_title}")
        return False

    def set_window_topmost(self):
        """置顶窗口"""
        if not self.hwnd:
            print("错误: 未设置有效窗口句柄")
            return False

        win32gui.SetWindowPos(
            self.hwnd, win32con.HWND_TOPMOST,
            0, 0, 0, 0,
            win32con.SWP_NOMOVE | win32con.SWP_NOSIZE
        )
        print("窗口已置顶")
        return True

    def launch_app(self):
        """启动应用"""
        command = f"adb shell am start -n {self.package}/{self.activity}"
        print(f"执行命令: {command}")
        return os.system(command) == 0

    # 新增:封装完整流程
    def full_process(self):
        """执行完整控制流程"""
        print("="*40)
        print("开始执行 Scrcpy 控制流程")

        # 步骤1-2: 窗口操作
        if self.find_window():
            self.set_window_topmost()
        else:
            print("警告: 跳过窗口置顶操作")

        # 步骤3: 启动应用
        if self.launch_app():
            print("应用启动成功")
        else:
            print("应用启动失败")

        print("流程执行完毕")
        print("="*40)

# ===== 主函数 =====
def main():
    # 创建控制器实例
    controller = ScrcpyController(WINDOW_TITLE, APP_PACKAGE, APP_ACTIVITY)

    # 执行完整流程
    controller.full_process()

# ===== 程序入口 =====
if __name__ == "__main__":
    main()
已深度思考(用时1分1秒)
我们将从面向对象的三大特性(封装、继承、多态)开始讲解,然后讨论MVC架构、依赖注入和命令模式,最后解释多文件项目的组织方式。

一、面向对象三大特性
1. 封装 (Encapsulation)
本意:将数据和操作数据的方法绑定在一起,并隐藏内部实现细节,只暴露必要的接口。
作用:提高代码安全性,降低耦合度,便于维护。
在您的场景中的使用:

Python
class WindowManager:
    def __init__(self, title):
        self.title = title
        self.hwnd = 0  # hwnd是内部状态,外部无法直接访问

    # 公开的方法,外部通过这个方法来操作
    def set_topmost(self):
        if not self.hwnd:
            self._find_window()  # 内部方法,外部不能调用
        # ...置顶操作...

    # 私有方法(约定为内部使用)
    def _find_window(self):
        self.hwnd = win32gui.FindWindow(None, self.title)
2. 继承 (Inheritance)
本意:允许创建子类继承父类的属性和方法,并可以扩展或重写。
作用:代码复用,实现层次化分类。
在您的场景中的使用:

Python
class BaseManager:
    def __init__(self):
        self.logger = self._create_logger()

    def _create_logger(self):
        return SimpleLogger()

    def log(self, message):
        self.logger.log(message)

class WindowManager(BaseManager):  # 继承BaseManager
    def __init__(self, title):
        super().__init__()  # 调用父类初始化
        self.title = title

    def set_topmost(self):
        self.log("开始置顶窗口")  # 复用父类的log方法
        # ...具体操作...
3. 多态 (Polymorphism)
本意:不同类的对象对同一消息(方法调用)做出不同的响应。
作用:提高代码的灵活性和可扩展性。
在您的场景中的使用:

Python
class DeviceController(ABC):
    @abstractmethod
    def prepare(self):
        pass

class WindowController(DeviceController):
    def prepare(self):  # 实现抽象方法
        print("准备窗口")

class AppController(DeviceController):
    def prepare(self):  # 同样的方法名,不同的实现
        print("准备应用")

def initialize_controllers(controllers: List[DeviceController]):
    for controller in controllers:
        controller.prepare()  # 多态调用

# 使用:
win_controller = WindowController()
app_controller = AppController()
initialize_controllers([win_controller, app_controller])
二、MVC模式
定义:

Model(模型):负责数据逻辑,如读取配置、保存数据。
View(视图):负责用户界面展示。
Controller(控制器):负责业务逻辑,协调Model和View。
适用场景:需要用户交互的应用程序,尤其是Web应用和桌面GUI应用。

在您的项目中:

Model:配置参数(config.py)、设备状态数据
View:控制台输出、未来可能的GUI界面
Controller:处理窗口和应用的控制器(controllers目录下的类)
示例结构:

Python
# model/config.py
class Config:
    WINDOW_TITLE = "scrcpy"
    APP_PACKAGE = "com.example.app"

# view/console_view.py
class ConsoleView:
    def show_message(self, msg):
        print(msg)

# controller/app_controller.py
class AppController:
    def __init__(self, config, view):
        self.config = config
        self.view = view

    def launch(self):
        self.view.show_message(f"启动应用: {self.config.APP_PACKAGE}")
        # ...启动逻辑...
三、依赖注入 (Dependency Injection)
定义:将依赖的对象通过外部传入,而不是在内部创建。
目的:降低耦合,便于测试和替换。

在您场景中的使用:

Python
# 不使用依赖注入
class AppController:
    def __init__(self):
        self.logger = ConsoleLogger()  # 内部创建,难以更换

# 使用依赖注入
class AppController:
    def __init__(self, logger):  # 由外部传入
        self.logger = logger

# 在main中创建并注入:
logger = FileLogger("app.log")
app_controller = AppController(logger)
优点:方便更换实现(如测试时用模拟Logger)。

四、命令模式 (Command Pattern)
定义:将请求封装为对象,以便使用不同的请求、队列或日志请求。
核心:解耦请求者和执行者。

在您场景中的使用:

Python
class Command(ABC):
    @abstractmethod
    def execute(self):
        pass

class LaunchAppCommand(Command):
    def __init__(self, app_controller):
        self.app_controller = app_controller

    def execute(self):
        self.app_controller.launch()

class SetTopmostCommand(Command):
    # 类似实现...

# 使用
commands = [
    SetTopmostCommand(window_controller),
    LaunchAppCommand(app_controller)
]

for cmd in commands:
    cmd.execute()
优点:可以轻松扩展新命令,支持撤销操作。

五、多文件项目组织
您展示的项目结构:

 my_project/
├── config.py       # 配置参数
├── controllers/    # 控制器类
│   ├── window.py
│   └── app.py
├── services/       # 服务类(完整流程)
├── utils/          # 工具函数
└── main.py         # 程序入口
如何调用?
在main.py中导入其他模块:
Python
# main.py
from config import Config
from controllers.window import WindowController
from services.scrcpy_service import ScrcpyService

def main():
    cfg = Config()
    window_controller = WindowController(cfg.WINDOW_TITLE)
    service = ScrcpyService(window_controller)
    service.run()

if __name__ == "__main__":
    main()
类内部封装:每个类在自己的文件中实现,通过导入使用。
例如:services/scrcpy_service.py:
Python
from controllers.window import WindowController
from controllers.app import AppController

class ScrcpyService:
    def __init__(self, window_title, app_package, app_activity):
        self.window_controller = WindowController(window_title)
        self.app_controller = AppController(app_package, app_activity)

    def full_process(self):
        # ...调用各个控制器的方法...
为什么这样组织?
模块化:功能相似的代码放在一起。
可维护性:文件大小适中,便于查找和修改。
可读性:结构清晰,新人容易理解。
总结对比
模式  主要目的    适用场景    优点  缺点
MVC 分离数据、界面和逻辑  用户交互应用(Web, GUI)    结构清晰,职责分明   小型项目可能过于复杂
依赖注入    解耦组件,便于替换和测试    需要灵活替换依赖组件的场景   提高可测试性,降低耦合 需要额外设置
命令模式    封装操作为对象,支持撤销队列  需要实现撤销/重做、事务等功能的场景  扩展性好,支持复杂操作 增加类的数量
在您的项目中的选择建议
小型工具:使用简单的封装和函数式组织(如您最初的版本)即可。
中型项目:采用服务类封装流程(如ScrcpyService),并分割文件。
大型或长期维护项目:考虑MVC、依赖注入等模式。
您的项目目前适合第二种方式:服务类封装核心流程,控制器类封装具体操作,分割为多个文件便于维护。

如果您还有疑问,可以提出具体想了解的某个部分,我会进一步详解。

下面我将全面解析面向对象三大特性、设计模式以及多文件项目组织,帮助您构建系统化的认知体系。

一、面向对象三大特性
1. 封装 (Encapsulation)
本意:隐藏内部实现细节,提供清晰接口
作用:提高安全性、降低耦合、简化使用
在场景中的应用:

Python
class WindowController:
    def __init__(self, title):
        self._title = title  # 封装属性
        self._hwnd = 0       # 外部无法直接访问

    # 公有方法作为接口
    def move_to_position(self, x, y):
        """对外提供的移动接口"""
        self._verify_window_exists()
        self._internal_move(x, y)  # 调用私有方法

    # 私有方法隐藏实现细节
    def _internal_move(self, x, y):
        """封装移动实现细节"""
        win32gui.MoveWindow(self._hwnd, x, y, self._width, self._height, True)
2. 继承 (Inheritance)
本意:实现代码复用和层级抽象
作用:减少重复代码、建立类层次关系
在场景中的应用:

Python
class BaseController:
    """控制器基类"""
    def __init__(self, logger):
        self.logger = logger

    def log_action(self, action_name):
        """通用日志方法"""
        self.logger.info(f"执行操作: {action_name}")

class WindowController(BaseController):  # 继承基类
    """窗口专用控制器"""
    def __init__(self, title, logger):
        super().__init__(logger)  # 调用父类初始化
        self.title = title

    def resize(self, width, height):
        self.log_action("调整窗口大小")  # 复用父类方法
        # 窗口调整具体实现
3. 多态 (Polymorphism)
本意:同一接口不同实现
作用:提高扩展性、简化调用
在场景中的应用:

Python
class DeviceControl(ABC):  # 抽象基类
    @abstractmethod
    def prepare(self):
        pass

class WindowControl(DeviceControl):
    def prepare(self):  # 多态实现
        print("准备窗口环境")

class AppControl(DeviceControl):
    def prepare(self):  # 多态实现
        print("准备应用环境")

# 统一调用接口
def initialize_environment(controllers: List[DeviceControl]):
    for controller in controllers:
        controller.prepare()  # 多态调用
二、MVC架构模式
定义
Model(模型):数据层,负责业务数据和业务逻辑
View(视图):显示层,负责数据展示
Controller(控制器):控制层,负责用户交互和调度
在您项目中的应用
Python
# models/config_model.py
class AppConfig:
    def __init__(self):
        self.window_title = "scrcpy"
        self.app_package = "com.example.app"
        self.app_activity = ".MainActivity"

    def to_dict(self):
        return {
            "title": self.window_title,
            "package": self.app_package,
            "activity": self.app_activity
        }

# views/console_view.py
class ConsoleView:
    def show_config(self, config: dict):
        print("当前配置:")
        for key, value in config.items():
            print(f"{key}: {value}")

    def show_error(self, message):
        print(f"[错误] {message}")

# controllers/window_controller.py
class WindowController:
    def __init__(self, config, view):
        self.config = config
        self.view = view

    def initialize(self):
        try:
            config_data = self.config.to_dict()
            self.view.show_config(config_data)
            # 实际窗口操作...
        except Exception as e:
            self.view.show_error(str(e))
适用场景
需要清晰分离业务逻辑和界面展示
多平台适配(不同View实现)
需要灵活替换数据源
团队协作开发(明确分工)
三、依赖注入 vs 命令模式
1. 依赖注入 (Dependency Injection)
定义:通过外部传入依赖对象,而非内部创建
场景:需要灵活替换组件实现时

Python
# services/logger_service.py
class Logger:
    def info(self, message):
        print(f"[INFO] {message}")

# controllers/app_controller.py
class AppController:
    def __init__(self, logger: Logger):  # 依赖注入
        self.logger = logger

    def launch(self):
        self.logger.info("启动应用中...")
        # 启动逻辑

# main.py
from services.logger_service import Logger
from controllers.app_controller import AppController

def main():
    logger = Logger()                     # 创建依赖对象
    app_controller = AppController(logger) # 注入依赖
    app_controller.launch()
优点:解耦、易测试、可替换实现
缺点:增加配置复杂度

2. 命令模式 (Command Pattern)
定义:将请求封装为对象,支持参数化和队列化
场景:需要支持撤销、重做、批处理等操作

Python
from abc import ABC, abstractmethod

class Command(ABC):
    @abstractmethod
    def execute(self):
        pass

class MoveWindowCommand(Command):
    def __init__(self, window, x, y):
        self.window = window
        self.x = x
        self.y = y
        self.prev_position = None

    def execute(self):
        self.prev_position = self.window.get_position()
        self.window.move(self.x, self.y)

    def undo(self):
        if self.prev_position:
            self.window.move(*self.prev_position)

# 使用
commands = [
    MoveWindowCommand(window, 100, 100),
    ResizeWindowCommand(window, 800, 600)
]

for cmd in commands:
    cmd.execute()
优点:解耦调用者和执行者、支持复杂操作
缺点:增加类的数量

四、多文件项目组织详解
项目结构
 my_project/
├── config.py           # 配置参数
├── controllers/        # 控制器类
│   ├── __init__.py     # 包初始化
│   ├── window.py       # 窗口控制器
│    └── app.py          # 应用控制器
├── services/           # 服务类
│   ├── __init__.py
│    └── scrcpy_service.py
├── utils/              # 工具函数
│   ├── __init__.py
│    └── logger.py
└── main.py             # 程序入口
文件交互示例
config.py (配置定义)
Python
# config.py
WINDOW_TITLE = "scrcpy"
APP_PACKAGE = "com.tencent.tmgp.sgamece"
APP_ACTIVITY = ".wxapi.WXEntryActivity"
controllers/window.py (窗口控制器)
Python
# controllers/window.py
import win32gui
import win32con

class WindowController:
    def __init__(self, title):
        self.title = title

    def find_window(self):
        hwnd = win32gui.FindWindow(None, self.title)
        return bool(hwnd)
services/scrcpy_service.py (服务整合)
Python
# services/scrcpy_service.py
from controllers.window import WindowController
from controllers.app import AppController

class ScrcpyService:
    def __init__(self, window_title, app_package, app_activity):
        self.window_controller = WindowController(window_title)
        self.app_controller = AppController(app_package, app_activity)

    def full_process(self):
        if self.window_controller.find_window():
            self.window_controller.set_topmost()
        self.app_controller.launch()
main.py (程序入口)
Python
# main.py
from config import WINDOW_TITLE, APP_PACKAGE, APP_ACTIVITY
from services.scrcpy_service import ScrcpyService

def main():
    service = ScrcpyService(WINDOW_TITLE, APP_PACKAGE, APP_ACTIVITY)
    service.full_process()

if __name__ == "__main__":
    main()
关键机制解析
导入路径:

Python通过模块路径导入
from 包名.模块名 import 类名
__init__.py 使目录成为Python包
模块关联:

main导入服务
服务导入控制器
控制器实现具体逻辑
封装层次:

控制器:单一功能实现
服务:组合多个控制器完成复杂流程
main:最高层流程控制
文件拆分原则:

单个文件不超过300行
按功能/职责划分
高内聚低耦合
企业级设计最佳实践
1. 架构选择指南
需求场景    推荐架构    示例应用
简单脚本(100行以下)    单文件过程式  一次性数据处理脚本
中小型工具(300-1000行)    服务层+控制器 本文的scrcpy控制器
复杂应用(1000行以上)   MVC+依赖注入    带UI的自动化测试工具
需要操作历史记录    命令模式    图像编辑工具

相关阅读