Bereichsübergreifende Aspekte beziehen sich bei einem Programm auf mehrere Teile des Systems (z. B. Protokollierung, Sicherheit, Datenüberprüfung und Fehlerbehandlung). Sie können in der gesamten Codebasis verstreut sein, was zu Codeduplizierung und Wartungsproblemen führt.
Copilot-Chat kann beim Refactoring von übergreifenden Anliegen helfen, indem er die Implementierung von Methoden der aspektorientierten Programmierung (Aspect-Oriented Programming, AOP) oder die Verwendung von Decorators und Middlewaremustern vorschlägt, um diese Anliegen modular und wartbar zu zentralisieren.
Beispielszenario
Stellen Sie sich vor, Sie haben eine Python-project, die mehrere Dienstdateien enthält, in denen die Protokollierung erfolgt. Die protokollierten Informationen werden in den einzelnen Dienstdateien definiert. Wenn die Anwendung in Zukunft geändert oder erweitert wird, kann dieser Entwurf zu Inkonsistenzen beim Inhalt und Stil von Protokolleinträgen führen. Sie können das Protokollierungsverhalten konsolidieren und zentralisieren, um zu vermeiden, dass dies über Ihre project verteilt wird.
Hier sind drei Dateien aus unserem Beispiel project: die Einstiegspunktdatei (main.py), die Konfigurationsdatei für Protokollnachrichten (logging_config.py) und eine der Dienstdateien (order_service.py). Die Beispieldienstdatei zeigt, wie Protokollinformationen zusammen mit der Geschäftslogik für einen bestimmten Teil der Anwendung definiert werden.
main.py
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
import logging
def setup_logging():
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
order_service.py
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.")
Beispielprompt
Öffne den Projektarbeitsbereich in VS Code oder Visual Studio, und gib den folgenden Prompt in der Copilot-Chat-Ansicht ein.
@workspace Refactor this project by using AOP to avoid logging that has cross-cutting concerns
@workspace Refactor this project by using AOP to avoid logging that has cross-cutting concerns
Hinweis
Der @workspace-Chatteilnehmer in VS Code und Visual Studio stellt Copilot Kontext für den gesamten Code in deinem Arbeitsbereich bereit. Sie können @workspace verwenden, wenn Sie möchten, dass Copilot die Struktur Ihres Projekts und die Interaktion der verschiedenen Teile des Codes berücksichtigt. Wenn Sie eine JetBrains-IDE verwenden, verwenden Sie @project anstelle von @workspace.
Beispielantwort
Copilot antwortet wie folgt.
Hinweis
Die folgende Antwort ist ein Beispiel. Da die Copilot-Chat-Antworten nicht deterministisch sind, erhältst du möglicherweise eine andere Antwort als die hier beschriebene.
Um dieses Projekt mithilfe von Aspect-Oriented Programming (AOP) umzugestalten, um die Protokollierung als eine querschnittliche Angelegenheit zu behandeln, können Sie eine Bibliothek wie
aspectlibverwenden. Hier erfährst du, wie du dies tun kannst:
Installieren Sie
aspectlib:
pip install aspectlibErstelle einen Aspekt für die Protokollierung in einer neuen Datei namens
logging_aspect.py: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}")Wende den Aspekt auf die Dienstmethoden in
main.pyan: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 weist dich dann an, den Protokollierungscode aus allen Dienstklassen zu entfernen, und stellt den Code für die überarbeiteten Dateien bereit. Dies ist beispielsweise die überarbeitete Version von order_service.py:
class OrderService:
def place_order(self, order):
# In here would be the business logic for placing an order
# ...
pass
In der umgestalteten Version des project werden dieselben Protokollierungsvorgänge ausgeführt, aber der Protokollierungscode wird in einer einzelnen Datei zentralisiert.