Is there an example of a system which uses Decorator design pattern that isn't suitable for Chain of Responsibility design pattern?
Note: I'm not searching for an explanation, I need an example to my specific problem.
To be fair, in practical use these two patterns are so closely related as to be almost indistinguishable. I usually just refer to classes that wrap other classes of the same type as Decorators. If we have to stick by the definitions in the book, though, they are different.
Decorators do some stuff before and after, while Chain of Responsibility either does something or calls the next element in the chain.
I recently used this small Decorator graph in a code base:
new EmailingReservationsRepository(
postOffice,
new LoggingReservationsRepository(
logger,
new SqlReservationsRepository(connStr)))
EmailingReservationsRepository
, LoggingReservationsRepository
, and SqlReservationsRepository
all implement the same interface:
public interface IReservationsRepository
{
Task Create(int restaurantId, Reservation reservation);
Task<IReadOnlyCollection<Reservation>> ReadReservations(
int restaurantId, DateTime min, DateTime max);
Task<Reservation?> ReadReservation(int restaurantId, Guid id);
Task Update(int restaurantId, Reservation reservation);
Task Delete(int restaurantId, Guid id);
}
When a client calls, say, Create
, EmailingReservationsRepository
first does this:
public async Task Create(int restaurantId, Reservation reservation)
{
await Inner.Create(restaurantId, reservation);
await PostOffice.EmailReservationCreated(restaurantId, reservation);
}
The Inner
instance is, in this case, the LoggingReservationsRepository
object, which does this:
public async Task Create(int restaurantId, Reservation reservation)
{
Logger.LogInformation(
"{method}(restaurantId: {restaurantId}, reservation: {reservation})",
nameof(Create),
restaurantId,
JsonSerializer.Serialize(reservation.ToDto()));
await Inner.Create(restaurantId, reservation);
}
and finally SqlReservationsRepository
saves the reservation
in a relational database.
You can't use Chain of Responsibility for this, because each element in the chain would have to either handle the method call or pass it on. It can't do both; if it does, it's no longer Chain of Responsibility.
In practice, the distinction between these two patterns is blurred to the extent that I don't really care. I just call most of these things Decorators and move on.