240 likes | 255 Views
Learn the fundamentals of design patterns in software engineering, including abstract structures, interactions, and conventions. Discover how to leverage previous work for reusability and efficiency in code development. With examples like adapter, observer, proxy, and more.
E N D
Design Patterns ECE 417/617:Elements of Software Engineering Stan Birchfield Clemson University
What is a Design Pattern? • A design pattern • abstracts a recurring design structure • comprises class and/or object • dependencies, • structures, • interactions, or • conventions • distills design experience
Re-use • Code re-use • Don’t reinvent the wheel • Requires clean, elegant, understandable, general, stable code • leverage previous work • Design re-use • Don’t reinvent the wheel • Requires a precise understanding of common, recurring designs • leverage previous work
Some design patterns • Abstract factory • Adapter • Bridge • Command • Composite • Façade • Subject / Observer • Proxy • Strategy
Subject-observer [from Vlissides]
Subject-observer (cont.) 1 * Subject Register(Observer) Unregister(Observer) NotifyAll() Observer OnUpdate() for all o in observers { o.OnUpdate() }
Subject-observer (cont.) 1 * Subject Register(Observer) Unregister(Observer) NotifyAll() Observer virtual OnUpdate() for all o in observers { o.OnUpdate() } ConcreteSubject ConcreteObserver virtual OnUpdate()
Model / view / controller (MVC) (displays data) View { Model m; Controller c(&m); View v(&c); } (mediates) Controller (holds data) Model calls Register() Main Create() View Create() Register() Create() Controller Model
MVC (cont.) 1 * Subject Register(Observer) Unregister(Observer) NotifyAll() Observer virtual OnUpdate() for all o in observers { o.OnUpdate() } Controller View virtual OnUpdate()
MVC (cont.) class Observer { protected: virtual void OnUpdate(MsgId message_id) = 0; }; class Subject { public: enum MsgId {}; void RegisterObserver(Observer* obs); virtual void NotifyAllObservers(MsgId message_id) { for (int i=0 ; i<m_observers.size() ; i++) { m_observers[i]->OnUpdate(message_id); } } private: std::vector<Observer*> m_observers; };
MVC (cont.) class Controller : public Subject { Controller(Data* d) : m_data(d) {} const Data* GetData() const; void AddSphere(const Sphere& s) { m_data->AddSphere(s); NotifyAllObservers(ADD_SPHERE); } private: Data* m_data; };
MVC (cont.) class MainWnd : public Observer { public: MainWnd(Controller* c) : m_controller(c) { c.Register(this); } virtual void OnUpdate(int message_id) { switch (message_id) { case Subject::ADD_SPHERE: ... } } private: Controller* m_controller; };
Adapter • You have • legacy code • current client • Adapter changes interface of legacy code so client can use it • Adapter fills the gap b/w two interfaces • No changes needed for either • legacy code, or • client
Adapter (cont.) class NewTime { public: int GetTime() { return m_oldtime.get_time() * 1000 + 8; } private: OldTime m_oldtime; };
Command • You have commands that need to be • executed, • undone, or • queued • Command design pattern separates • Receiver from Invoker from Commands • All commands derive from Command and implement do(), undo(), and redo()
Facade • You • have a set of related classes • want to shield the rest of the system from these details • Facade provides a simplified interface • Encapsulates a subsystem
Composite • You want uniformly to treat • items (atomic elements), and • groups (containing items or other groups) • Composite interface specifies operations that are shared between items and groups • Examples: hierarchy of files and directories, groups of drawable elements
Composite (cont.) Composite Item Group
Proxy • You want to • delay expensive computations, • use memory only when needed, or • check access before loading an object into memory • Proxy • has same interface as Real object • stores subset of attributes • does lazy evaluation
Strategy • You want to • use different algorithms depending upon the context • avoid having to change the context or client • Strategy • decouples interface from implementation • shields client from implementations • Context is not aware which strategy is being used; Client configures the Context • strategies can be substituted at runtime • example: interface to wired and wireless networks
Strategy (cont.) Client Policy Strategy Context Concrete StrategyA Concrete StrategyB
Bridge • You • have several different implementations • need to choose one, possibly at run time • Bridge • decouples interface from implementation • shields client from implementations • Abstraction creates and initializes the ConcreteImplementations • Example: stub code, slow code, optimized code
Bridge (cont.) Client Implementor Abstraction Concrete ImplementorA Concrete ImplementorB Refined Abstraction
Design pattern space [from Vlissides]