[每天记录一个问题,记录十年 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的自动化测试工具
需要操作历史记录 命令模式 图像编辑工具

