Refactoring Task
Overviewβ
This exercise addresses a design in which the OrderService
directly creates and utilizes an InventoryService
instance during order processing.
You will examine this structure from the perspective of dependency decoupling, abstraction, and injection, and propose refactoring strategies.
Initial Codeβ
The following example shows an OrderService
class that handles order placement and directly reduces inventory by creating an InventoryService
instance.
This tight coupling raises concerns around maintainability, reusability, and testability.
- TypeScript
- PHP
- Python
class InventoryService {
reduceStock(productId: string, amount: number) {
console.log(`ε¨εΊ«γζΈγγγΎγγ: ${productId} Γ ${amount}`);
}
}
class OrderService {
private inventory: InventoryService;
constructor() {
this.inventory = new InventoryService();
}
placeOrder(productId: string, quantity: number) {
console.log(`注ζεδ»: ${productId} Γ ${quantity}`);
this.inventory.reduceStock(productId, quantity);
}
}
<?php
class InventoryService {
public function reduceStock(string $productId, int $amount): void {
echo "ε¨εΊ«γζΈγγγΎγγ: {$productId} Γ {$amount}\n";
}
}
class OrderService {
private InventoryService $inventory;
public function __construct() {
$this->inventory = new InventoryService();
}
public function placeOrder(string $productId, int $quantity): void {
echo "注ζεδ»: {$productId} Γ {$quantity}\n";
$this->inventory->reduceStock($productId, $quantity);
}
}
class InventoryService:
def reduce_stock(self, product_id: str, amount: int):
print(f"ε¨εΊ«γζΈγγγΎγγ: {product_id} Γ {amount}")
class OrderService:
def __init__(self):
self.inventory = InventoryService()
def place_order(self, product_id: str, quantity: int):
print(f"注ζεδ»: {product_id} Γ {quantity}")
self.inventory.reduce_stock(product_id, quantity)
Question 1: What are the structural problems in this code?β
Identify and explain the key design issues using the following points as a guide:
- Tight dependency on implementation, making mocking or substitution difficult
- Low reusability, resulting in poor decoupling and flexibility
- Violations of DIP (Dependency Inversion Principle) and OCP (Open/Closed Principle)
- Blurred responsibility boundaries, hindering testability and maintainability
Question 2: How can this structure be refactored to improve flexibility and maintainability?β
Provide a refactoring plan considering the following:
- How can the dependent class be injected from the outside instead of instantiated internally?
- How can we reverse the direction of dependency to achieve more modular design?
- How can we support multiple implementations (e.g.,
MockInventoryService
,RemoteInventoryAPI
)?
Example: Candidate Design Patternsβ
Pattern Name | Purpose and Effect |
---|---|
Observer | Decouples components via event notifications, reducing direct dependencies |
Mediator | Centralizes coordination between services, avoiding direct inter-class references |
Dependency Injection | Allows injection of dependencies from outside, improving flexibility and testability |
Abstract Factory | Enables switching between object configurations by delegating creation logic |
Optional Extensionsβ
- If
ShippingService
orPaymentService
were added, how would you restructure the dependencies? - If multiple implementations of
InventoryService
exist (e.g., local vs. remote API), how would you switch between them dynamically?
Suggested Output Format (for review or team discussion)β
- List of structural issues (at least three)
- Refactoring strategy and rationale for chosen pattern(s)
- Conceptual design of the improved structure (e.g., injection method or dependency diagram)