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

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

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

Oleg Dashevskii

March 24, 2014
Tweet

More Decks by Oleg Dashevskii

Other Decks in Education

Transcript

  1. ШАБЛОНЫ (ПАТТЕРНЫ) ПРОЕКТИРОВАНИЯ • Нет смысла решать схожие задачи каждый

    раз заново. • Ограниченное количество «сюжетов» порождает безграничное количество «историй». • Узнать шаблон.
  2. Кристофер Александер Любой шаблон описывает задачу, которая снова и снова

    возникает в работе, и принцип ее решения, причем так, что решение можно использовать миллион раз, ничего не изобретая заново. !
  3. УЖЕ ИЗВЕСТНЫЕ ШАБЛОНЫ • Singleton (одиночка). Порождение объектов. Единственный экземпляр

    класса. • Iterator (итератор). Обход структуры данных, скрывающий её внутреннее устройство.
  4. struct is_positive_number {! bool operator()(int x) { return 0 <

    x; }! };! ! int main()! {! int nums[] = { 0, -1, 4, -3, 5, 8, -2 };! const int N = sizeof(nums) / sizeof(nums[0]);! ! int *numbers = nums;! ! typedef boost::filter_iterator<is_positive_number, int *> FilterIter;! ! is_positive_number predicate;! FilterIter filter_iter_first(predicate, numbers, numbers + N);! FilterIter filter_iter_last(predicate, numbers + N, numbers + N);! ! std::copy(filter_iter_first, filter_iter_last,! std::ostream_iterator<int>(std::cout, " "));! std::cout << std::endl;! }! Ленивые вычисления с помощью итераторов
  5. ШАБЛОН «КОМАНДА»
 (COMMAND) • Команда инкапсулирует запрос как самостоятельный объект.

    • Выполнение запроса «отрывается» от его создания. • Запросы могут помещаться в очередь, протоколироваться, отменяться.
  6. class TextBuffer {! // ...! };! ! class EditorCommand {!

    public:! EditorCommand(TextBuffer *);! virtual void redo() = 0;! virtual void undo() = 0;! ! private:! TextBuffer *textbuf;! };! ! class DeleteTextCommand : public EditorCommand {! // ...! };! ! class SearchAndReplaceCommand : public EditorCommand {! // ...! };! ! class InsertBlockCommand : public EditorCommand {! // ...! };! ! // .... other commands ....!
  7. class Editor {! public:! // ....! void onCtrlVPressed() {! addAndExecuteCommand(new

    InsertBlockCommand(clipboardContents()));! }! ! void addAndExecuteCommand(EditorCommand *cmd) {! if (currentCommandIdx == commands.size() - 1) {! commands.push_back(cmd);! currentCommandIdx++;! } else {! delete commands[++currentCommandIdx];! commands[currentCommandIdx] = cmd;! commands.resize(currentCommandIdx + 1);! }! ! cmd->redo();! }! ! void undo() {! if (currentCommandIdx >= 0)! commands[currentCommandIdx--]->undo();! }! private:! std::vector<EditorCommand *> commands;! int currentCommandIdx;! };!
  8. МИГРАЦИИ В SQL БД # db/migrate/20140212031808_add_send_status_mails_to_member_roles.rb! ! class AddSendStatusMailsToMemberRoles <

    ActiveRecord::Migration! def up! add_column :member_roles, :send_status_mails, :boolean, default: true! ! execute "UPDATE member_roles SET send_status_mails='t'"! ! change_column :member_roles, :send_status_mails, :boolean, default: true, null: false! end! ! def down! remove_column :member_roles, :send_status_mails! end! end!
  9. ОТЛОЖЕННАЯ ОБРАБОТКА • Клиент: • создаёт объект «Команда». • сериализует

    объект в бинарное представление. • кладёт в очередь (БД, хранилище Redis, …) • Обработчик: (через какое-то время, другой процесс, другой компьютер) • достаёт из очереди объект «Команда». • десериализует. • выполняет.
  10. • Объект «Команда» должен содержать всё необходимое для выполнения и

    отката команды, ибо контекст исполнения отличается от контекста порождения. • Макрокоманда — цепочка из нескольких команд. • Транзакционность — макрокоманда либо будет выполнена до конца (с изменением состояния), либо не будет выполнена вообще (состояние останется неизменным). • Если 8-я команда завершилась с ошибкой, откатываем обратно с 7-й по 1-ю.
  11. TEMPLATE METHOD • Шаблонный метод определяет основу алгоритма и позволяет

    подклассам переопределить некоторые его шаги. • Концепция хуков (hooks).
  12. class Account {! public:! virtual void start() = 0;! virtual

    void allow() = 0;! virtual void end() = 0;! virtual int maxLimit() = 0;! ! // Template Method! void withdraw(int amount) {! start();! if (amount < maxLimit())! allow();! else! cout << "Not allowed"! << endl;! end();! }! }; class AccountNormal : public Account {! public:! void start() {! cout << "Start ..." << endl;! }! void allow() {! cout << "Allow ..." << endl;! }! void end() { ! cout << "End ..." << endl;! }! int maxLimit() { return 1000; }! };! ! class AccountPower : public Account {! public:! void start() {! cout << "Start ..." << endl;! }! void allow() {! cout << "Allow ..." << endl;! }! void end() {! cout << "End ..." << endl;! }! int maxLimit() { return 5000; }! }; int main() {! AccountPower power;! power.withdraw(1500);! ! AccountNormal normal;! normal.withdraw(1500);! }
  13. void print_number(int i) {! cout << i << ' ';!

    }! ! for_each(numbers.begin(), numbers.end(),! print_number);! ! // ---------------------------------------------------! ! bool is_odd(int i) { return i % 2 == 1; }! ! std::vector<int>::iterator bound;! bound = std::partition(numbers.begin(),! numbers.end(),! is_odd); STL же!
  14. • record.save() • record.valid?() • before_validation • record.validate() • after_validation

    • before_save • before_create • record.create() • after_create • after_save • after_commit ActiveRecord ORM: 
 hooks, вызываемые 
 при сохранении 
 новой записи
  15. • Инвертированная структура кода: родительский класс вызывает методы подкласса, а

    не наоборот. Принцип Голливуда: «Не звоните нам, мы сами вам позвоним». • Hooks (callbacks, крючки, зацепки) — определяются по желанию. Как правило, в базовом классе это функции с пустыми телами. • virtual foo() = 0; заставляет определять функции в подклассе. Принцип
 инверсии
 зависимостей
  16. STATE • Состояние позволяет объекту варьировать свое поведение в зависимости

    от внутреннего состояния. • Как будто бы меняется класс объекта.
  17. class Machine;! class OffState;! ! class BaseState {! Machine *machine;!

    public:! BaseState(Machine *m) : machine(m) {}! virtual void on() = 0;! virtual void off() = 0;! };! ! class OnState : public BaseState {! public:! void on() { cout << "Machine Already ON!" << endl; }! void off() {! machine->setState(new OffState(machine));! cout << "Machine Turned OFF!" << endl;! }! };! ! class OffState : public BaseState {! public:! void off() { cout << "Machine Already OFF!" << endl; }! void on() {! machine->setState(new OnState(machine));! cout << "Machine Turned ON!" << endl;! }! };
  18. class Machine {! BaseState *state;! public:! Machine() {! state =

    new OffState(this);! }! ~Machine() { delete state; }! ! void on() { state->on(); }! void off() { state->off(); }! ! void setState(BaseState *new_state) {! delete state;! state = new_state;! }! };!
  19. • Избавляемся от кучи if-ов. • Легко добавить новое состояние.

    • Переходы между состояниями может делать как основной класс, так и классы состояний. • Классы состояний можно наследовать друг от друга (если поведение несильно отличается). • Можно сделать классы состояний синглтонами (если все данные лежат в основном классе). Принцип
 открытия-
 закрытия