Even if you give a Customer
the methods addToCart()
and removeFromCart()
, you would still have to have some logic in ShoppingCart
to have these methods actually do the state change when an item is added or removed. IMO, the actor in this case is much better represented by a reference to the owning Customer and/or viceversa, e.g.
$cart = new ShoppingCart;
$cart->setOwner(new Customer);
$cart->addItem(new Item('Apples'));
$cart->checkout();
You could approach this from the customer as well, e.g.
$customer = new Customer;
$customer->setShoppingCart(new ShoppingCart);
$customer->addItemToShoppingCart(new Item('Apples'));
$customer->checkout();
But the method name addItemToShoppingCart
already implies that the Customer
acts on a ShoppingCart
, so inside you are likely doing
$this->getShoppingCart()->addItem($item);
If ShoppingCart
was a composite element of Customer
for which we wanted to hide implementation details, we could use something like that, but since the ShoppingCart
is IMO not an essential part of a Customer this method shouldnt be on Customer. It's nothing but a convenience proxy.
You could create a Decorator for the Customer
to handle the Shopping Behavior. This would decouple the concern/responsibility of How-To-Shop from the Customer, e.g. something like
class ShoppingDecorator
{
protected $actor;
protected $cart;
protected function __construct($actor) { ... }
public function getCart() { ... };
public function addToCart() { ... }
...
}
This would also allow you to apply the Shopping Behavior to other actors that might need this behavior.
The CustomerActsOnCart
approach sounds somewhat like the Mediator Pattern. Not sure if it's a feasible approach though.