# 处理横切关注点

Copilot Chat 可帮助你避免编写与代码所在方法或函数的核心关注点无关的代码。

横切关注点是影响系统多个部分的程序方面，例如日志记录、安全、数据验证和错误处理。 它们可能会分散在代码库中，导致代码重复和维护挑战。

Copilot Chat 通过建议实现 Aspect-Oriented 编程（AOP）做法或使用修饰器和中间件模式以模块化、可维护的方式集中这些关注点，可以帮助重构交叉关注点。

## 示例方案

假设你有一个 Python 项目，其中包含多个发生日志记录的服务文件。 记录的信息在每个单独的服务文件中定义。 如果将来修改或扩展应用程序，此设计可能会导致日志条目的内容和样式不一致。 您可以将日志记录行为合并和集中，以避免将其分散到项目中。

下面是示例项目中的三个文件：入口点文件 (`main.py`)、日志消息配置文件 (`logging_config.py`) 和一个服务文件 (`order_service.py`)。 示例服务文件演示如何将日志信息与应用程序特定部分的业务逻辑一起定义。

### main.py

```python
import logging
from logging_config import setup_logging
from payment_service import PaymentService
from order_service import OrderService
from shipping_service import ShippingService
from inventory_service import InventoryService
from notification_service import NotificationService

def main():
    setup_logging()
    payment_service = PaymentService()
    order_service = OrderService()
    shipping_service = ShippingService()
    inventory_service = InventoryService()
    notification_service = NotificationService()

    # Example usage
    payment_service.process_payment({"amount": 100, "currency": "USD"})
    order_service.place_order({"item": "Book", "quantity": 1})
    shipping_service.ship_order({"item": "Book", "quantity": 1})
    inventory_service.update_inventory("Book", -1)
    notification_service.send_notification("Order has been placed and shipped.")

if __name__ == "__main__":
    main()
```

### logging\_config.py

```python
import logging

def setup_logging():
    logging.basicConfig(level=logging.INFO,
                  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
```

### order\_service.py

```python
import logging

class OrderService:
    def __init__(self):
        self.logger = logging.getLogger(__name__)

    def place_order(self, order):
        self.logger.info("Entering place_order method.")
        try:
            # In here would be the business logic for placing an order
            # ...
            self.logger.info("Order placed successfully.")
        except Exception as e:
            self.logger.error(f"Error in place_order method: {e}")
            raise
        finally:
            self.logger.info("Exiting place_order method.")
```

## 示例提示

在 VS Code 或 Visual Studio 中打开项目工作区，并在 Copilot Chat 视图中输入以下提示词。

```copilot copy
@workspace Refactor this project by using AOP to avoid logging that has cross-cutting concerns
```

> \[!NOTE]
> 在 `@workspace` 和 VS Code 的聊天参与者向 Visual Studio 提供有关您工作区中所有代码的上下文。 你可以使用`@workspace`，当你希望Copilot考虑项目的结构以及代码的不同部分如何交互时。 如果使用 JetBrains IDE，请使用 `@project`，而不是 `@workspace`。

## 示例响应

Copilot 响应如下。

> \[!NOTE] 以下响应是示例。 Copilot Chat 的回答是不确定的，因此你可能会得到与这里所显示的不同的回答。

> 若要使用面向方面编程 (AOP) 来重构此项目以将日志记录作为横切关注点来处理，可以使用 `aspectlib` 之类的库。 以下是具体操作方法：
>
> 1. 安装 `aspectlib`：
>
>    `pip install aspectlib`
>
> 2. 在名为 `logging_aspect.py` 的新文件中创建用于日志记录的配置：
>
>    ```python
>    import aspectlib
>    import logging
>
>    @aspectlib.Aspect(bind=True)
>    def log_method_call(cutpoint, *args, **kwargs):
>        logger = logging.getLogger()
>        method_name = cutpoint.__name__
>        logger.info(f"Entering method: {method_name}")
>        try:
>            result = yield aspectlib.Proceed
>            logger.info(f"Method {method_name} executed successfully.")
>            return result
>        except Exception as e:
>            logger.error(f"Error in method {method_name}: {e}")
>            raise
>        finally:
>            logger.info(f"Exiting method: {method_name}")
>    ```
>
> 3. 将该方面应用于 `main.py` 中的服务方法：
>
>    ```python
>    import logging
>    from logging_config import setup_logging
>    from payment_service import PaymentService
>    from order_service import OrderService
>    from shipping_service import ShippingService
>    from inventory_service import InventoryService
>    from notification_service import NotificationService
>    from logging_aspect import log_method_call
>    import aspectlib
>
>    def main():
>        setup_logging()
>
>        # Apply logging aspect to service methods
>        aspectlib.weave(PaymentService.process_payment, log_method_call)
>        aspectlib.weave(OrderService.place_order, log_method_call)
>        aspectlib.weave(ShippingService.ship_order, log_method_call)
>        aspectlib.weave(InventoryService.update_inventory, log_method_call)
>        aspectlib.weave(NotificationService.send_notification, log_method_call)
>
>        payment_service = PaymentService()
>        order_service = OrderService()
>        shipping_service = ShippingService()
>        inventory_service = InventoryService()
>        notification_service = NotificationService()
>
>        # Example usage
>        payment_service.process_payment({"amount": 100, "currency": "USD"})
>        order_service.place_order({"item": "Book", "quantity": 1})
>        shipping_service.ship_order({"item": "Book", "quantity": 1})
>        inventory_service.update_inventory("Book", -1)
>        notification_service.send_notification("Order has been placed and shipped.")
>
>    if __name__ == "__main__":
>        main()
>    ```

Copilot 然后，告知你从所有服务类中删除日志记录代码，并为修改后的文件提供代码。 例如，这是 `order_service.py` 的修订版本：

```python
class OrderService:
    def place_order(self, order):
        # In here would be the business logic for placing an order
        # ...
        pass
```

在该项目的重构版本中，执行相同的日志记录操作，但将日志记录代码集中在一个文件中。

## 延伸阅读

* [GitHub Copilot 对话助手的提示设计](/zh/copilot/concepts/prompting/prompt-engineering)
* [使用 GitHub Copilot 的最佳做法](/zh/copilot/get-started/best-practices)