avoid coupling the sender of a request to its receiver by giving multiple objects a chance to handle the request, chaining the receivers and passing the request along the chain until one handles it
enable or disable features at runtime without deploying new code, allowing dynamic control over functionality for testing, gradual rollouts, or experimentation
defines an object that encapsulates how a set of objects interact, promoting loose coupling by preventing objects from referring to each other explicitly
defines a one-to-many dependency between objects so that when one object (the subject) changes state, all its dependents (observers) are notified and updated automatically
defines an overall fixed algorithm in a base class, deferring some steps to subclasses, so subclasses can redefine parts of the algorithm without changing its overall structure
represent an operation to be performed on elements of an object structure, letting you define new operations without changing the classes of the elements
allow adding new operations to a set of classes without creating cyclic dependencies between the visitor and elements, enabling flexible extension of visitor behavior for only the elements you care about