Upgrade to Pro — share decks privately, control downloads, hide ads and more …

АФТИ ООП 2013-2014. Лекция II/07

АФТИ ООП 2013-2014. Лекция II/07

Oleg Dashevskii

March 31, 2014
Tweet

More Decks by Oleg Dashevskii

Other Decks in Education

Transcript

  1. STRATEGY • Стратегия определяет семейство алгоритмов, инкапсулирует каждый из них

    и делает взаимозаменяемыми. • Алгоритмы изменяются независимо от клиентов, которые ими пользуются.
  2. enum FormatStyle {! LEFT_JUSTIFY, RIGHT_JUSTIFY, CENTER! };! ! std::string formatText(const

    std::string &text, FormatStyle style) {! ! // ...! ! if (style == LEFT_JUSTIFY) {! // ...! } else if (style == CENTER) {! // ...! }! ! // ...! ! switch (style) {! case LEFT_JUSTIFY:! // ...! case RIGHT_JUSTIFY:! // ...! case CENTER:! // ...! }! ! // ...! ! if (style != CENTER) {! // ....! }! ! // ...! } Принцип
 открытия-
 закрытия
  3. class FormattingStrategy {! public:! ! FormattingStrategy(int width) { /* ...

    */ }! ! ! virtual std::string justify(std::string text) = 0;! };! ! class LeftJustifyStrategy : public FormattingStrategy {! public:! ! // ...! };! ! class RightJustifyStrategy : public FormattingStrategy {! public:! ! // ...! };! ! class CenterStrategy : public FormattingStrategy {! public:! ! // ...! };! ! class TextFormatter {! public:! ! enum {! ! ! LEFT_JUSTIFY,! ! ! RIGHT_JUSTIFY,! ! ! CENTER,! ! ! // ....! ! };! ! ! void setStrategy(int type, int width);! ! std::string justify(std::string text) = 0;! };
  4. • Можно было бы сделать • LeftJustifyTextFormatter • RightJustifyTextFormatter •

    CenterTextFormatter • … унаследованные от базового класса TextFormatter, • … но … ?
  5. • … Тогда: • смешивается алгоритм и контекст; • нельзя

    динамически поменять алгоритм; • если используется несколько не связанных алгоритмов (напр.: форматирование по ширине и расстановка переносов), возникает картезианский взрыв классов- наследников.
  6. • Алгоритм фиксирован, отдельные шаги в подклассах могут меняться. •

    Алгоритм не фиксирован, в рамках интерфейса меняется что угодно. Шаблонный метод Стратегия
  7. template <typename T>! struct OpNewCreator {! static T *create() {

    return new T; }! };! ! template <typename T>! struct MallocCreator {! static T *create() {! void *buf = std::malloc(sizeof(T));! if (!buf) return 0;! return new(buf) T;! }! };! ! template <typename T>! struct PrototypeCreator {! PrototypeCreator(T *proto = 0)! : prototype(proto) {}! ! T *create() {! return prototype ? prototype->clone() : 0;! }! ! T *getPrototype() { return prototype; }! void setPrototype(T *proto) { prototype = proto; }! private:! T *prototype;! }; Стратегии 
 на темплейтах
  8. template <template <typename Created> CreationPolicy>! class WidgetManager : public CreationPolicy

    {! // ....! }; ! ! typedef WidgetManager<OpNewCreator> MyWidgetMgr;! Шаблон — аргумент шаблона
  9. template <typename T,! template <typename> class CheckingPolicy,! template <typename> class

    ThreadingModel>! class SmartPtr;! ! typedef SmartPtr<Widget, NoChecking, SingleThreaded> WidgetPtr;! typedef SmartPtr<Widget, EnforceNotNull, SingleThreaded> SafeWidgetPtr;! Две ортогональных стратегии для SmartPtr
  10. template <typename T>! struct NoChecking {! static void check(T *)

    {}! };! ! ! template <typename T>! struct EnforceNotNull {! class NullPointerException : public std::exception { /*...*/ };! ! static void check(T *ptr) {! if (!ptr)! throw NullPointerException();! }! };! ! ! template <typename T>! struct EnsureNotNull {! static void check(T *&ptr) {! if (!ptr)! ptr = getDefaultValue();! }! };!
  11. template <typename T,! template <typename> class CheckingPolicy,! template <typename> class

    ThreadingModel>! class SmartPtr! : public CheckingPolicy<T>,! public ThreadingModel<SmartPtr>! {! // ...! T *operator->() {! typename ThreadingModel<SmartPtr>::Lock guard(*this);! CheckingPolicy<T>::check(pointee);! return pointee;! }! ! private:! T *pointee;! };
  12. • Необходимо раскладывать классы на ортогональные стратегии, не нуждающиеся в

    информации друг о друге. • Повышается эффективность программы, ибо связывание делается на этапе компиляции, механизм виртуальных функций не нужен. • Теряется возможность динамического изменения стратегий во время выполнения.
  13. INTERPRETER • Интерпретатор обрабатывает команды, заданные на каком-то простом языке

    (на основе грамматики). BooleanExp ::= VariableExp | Constant | OrExp | AndExp | NotExp | '(' BooleanExp ')' AndExp ::= BooleanExp 'and' BooleanExp OrExp ::= BooleanExp 'or' BooleanExp NotExp ::= 'not' BooleanExp Constant ::= 'true' | 'false' VariableExp ::= 'A' | 'B' | ... | 'Y' | 'Z'
  14. class BooleanExp {! public:! BooleanExp();! virtual ~BooleanExp();! ! virtual bool

    evaluate(Context &) = 0;! };! ! class Context {! public:! bool lookup(const char *) const;! void assign(VariableExp *, bool);! };! ! class VariableExp : public BooleanExp {! public:! VariableExp(const char *variable_name) { /* ... */ }! virtual ~VariableExp();! // ....! };! ! class AndExp : public BooleanExp {! public:! AndExp(BooleanExp *, BooleanExp *);! // ....! };! ! class OrExp : public BooleanExp { /* ... */ };! class NotExp : public BooleanExp { /* ... */ };! class Constant : public BooleanExp { /* ... */ };
  15. BooleanExp *expression;! Context ctx;! ! VariableExp *x = new VariableExp("X");!

    VariableExp *y = new VariableExp("Y");! ! // (true and x) or (y and (not x))! expression = new OrExp(new AndExp(new Constant(true), x),! new AndExp(y, new NotExp(x)));! ctx.assign(x, false);! ctx.assign(y, true);! ! bool result = expression->evaluate(ctx);!
  16. • Преимущества компиляции: • Эффективность получающегося кода. • Преимущества интерпретации:

    • Динамичность. Возможность изменять исходный код во время исполнения. • Объединяем вместе…?
  17. • «Скриптовые» языки:
 Lua, Python, Ruby, JavaScript… • «Биндинги»: привязка

    функций и методов, существующих внутри скрипта, к методам в программе на C++. • В нужный момент вызывается скрипт, который оперирует высокоуровневыми функциями.
  18. VISITOR • Посетитель описывает операцию, выполняемую с каждым объектом из

    некоторой структуры данных. • Можно определить новую операцию, не изменяя классы объектов.
  19. Node —————— typeCheck() generateCode() prettyPrint() VariableRefNode ——————— typeCheck() generateCode() prettyPrint()

    AssignmentNode ——————— typeCheck() generateCode() prettyPrint() Реализация
 операций
 раскидана 
 по классам
  20. class Equipment {! public:! virtual Watt power();! virtual Currency netPrice();!

    virtual Currency discountPrice();! ! virtual void accept(EquipmentVisitor &);! // ...! };! ! class FloppyDisk : public Equipment { /* ... */ };! class Card : public Equipment { /* ... */ };! class Chassis : public Equipment { /* ... */ };! class Bus : public Equipment { /* ... */ };! ! class EquipmentVisitor {! public:! virtual void visitFloppyFisk(FloppyDisk *);! virtual void visitCard(Card *);! virtual void visitChassis(Chassis *);! virtual void visitBus(Bus *);! // ...! };!
  21. void FloppyDisk::accept(EquipmentVisitor &visitor) {! visitor.visitFloppyFisk(this);! }! ! void Chassis::accept(EquipmentVisitor &visitor)

    {! for (i = 0; i < elements.size(); ++i)! elements[i]->accept(visitor);! ! visitor.visitChassis(this);! }! ! // ....
  22. class PricingVisitor : public EquipmentVisitor {! public:! PricingVisitor();! ! Currency

    &getTotalPrice();! ! virtual void visitFloppyFisk(FloppyDisk *);! // ....! ! private:! Currency total; ! };! ! class InventoryVisitor : public EquipmentVisitor {! // ....! };
  23. • «Двойная диспетчеризация». • Легко добавлять новые операции (также можно

    наследовать). • Сложно добавлять новые классы данных :( • Аккумулирование состояния. • Каждый участник несёт ответственность за обход всех элементов структуры.