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

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

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

Oleg Dashevskii

April 07, 2014
Tweet

More Decks by Oleg Dashevskii

Other Decks in Education

Transcript

  1. ABSTRACT FACTORY • Абстрактная фабрика предоставляет интерфейс для создания семейств

    взаимосвязанных (взаимозависимых) объектов, не специфицируя их конкретных классов.
  2. class Car { // AbstractProductA! public:! virtual void printName() =

    0;! };! ! class Ford : public Car { // ProductA1! public:! virtual void printName() { cout << "Ford" << endl; }! };! ! class Toyota : public Car { // ProductA2! public:! virtual void printName() { cout << "Toyota" << endl; }! };!
  3. class Engine { // AbstractProductB! public:! virtual void printPower() =

    0;! };! ! class FordEngine : public Engine { // ProductB1! public:! virtual void printPower() {! cout << "Ford Engine 4.4" << endl;! }! };! ! class ToyotaEngine : public Engine { // ProductB2! public:! virtual void printPower() {! cout << "Toyota Engine 3.2" << endl;! }! };
  4. class CarFactory { // AbstractFactory! public:! virtual Car *createCar() const

    = 0;! virtual Engine *createEngine() const = 0;! };! ! class FordFactory : public CarFactory { // ConcreteFactory1! public:! virtual Car *createCar() const {! return new Ford();! }! virtual Engine *createEngine() const {! return new FordEngine();! }! };! ! class ToyotaFactory : public CarFactory { // ConcreteFactory2! public:! virtual Car *createCar() const {! return new Toyota();! }! virtual Engine *createEngine() const {! return new ToyotaEngine();! }! };
  5. void use(const CarFactory &f)! {! Car *myCar = f.createCar();! Engine

    *myEngine = f.createEngine();! ! myCar->printName();! myEngine->printPower();! ! delete myCar;! delete myEngine;! }! ! int main() {! ToyotaFactory toyotaFactory;! FordFactory fordFactory;! ! use(toyotaFactory);! use(fordFactory);! ! return 0;! }
  6. • Изоляция конкретных классов (клиент их даже не видит). •

    Легкая замена одного семейства продуктов на другое. • Гарантированная сочетаемость продуктов. • Трудно добавить новый вид продуктов. • Фабрике хорошо быть одиночкой (Singleton).
  7. BUILDER • Строитель — шаблон, порождающий объекты. • Конструирование сложного

    объекта отделяется от его представления. • В результате одного и того же процесса конструирования могут получаться различные представления.
  8. Builder ——————— buildPartA() buildPartB() ConcreteBuilder1 ——————— buildPartA() buildPartB() Director ———————

    construct() builder вызывает 
 builder.buildPartA() и 
 builder.buildPartB() Client Распорядитель Строитель ConcreteBuilder2 ——————— buildPartA() buildPartB()
  9. struct Wheel {! int size;! };! ! struct Engine {!

    int horsepower;! };! ! struct Body {! enum { SUV, HATCHBACK, SEDAN } shape;! const string &toString();! };! ! struct Car {! Wheel *wheels[4];! Engine *engine;! Body *body;! ! void specifications() {! cout << "body:" << body->toString() << endl;! cout << "engine horsepower:" << engine->horsepower << endl;! cout << "tire size:" << wheels[0]->size << "'" << endl;! }! }; class Builder {! public:! virtual Wheel *getWheel() = 0;! virtual Engine *getEngine() = 0;! virtual Body *getBody() = 0;! };
  10. class JeepBuilder : public Builder {! public:! Wheel *getWheel() {!

    Wheel *wheel = new Wheel();! wheel->size = 22;! return wheel;! }! ! Engine *getEngine() {! Engine *engine = new Engine();! engine->horsepower = 400;! return engine;! }! ! Body *getBody() {! Body *body = new Body();! body->shape = Body::SUV;! return body;! }! };
  11. class NissanBuilder : public Builder {! public:! Wheel *getWheel() {!

    Wheel* wheel = new Wheel();! wheel->size = 16;! return wheel;! }! ! Engine *getEngine() {! Engine* engine = new Engine();! engine->horsepower = 85;! return engine;! }! ! Body *getBody() {! Body *body = new Body();! body->shape = Body::HATCHBACK;! return body;! }! };
  12. class Director {! Builder *builder;! public:! void setBuilder(Builder *newBuilder) {!

    builder = newBuilder;! }! ! Car *getCar() {! Car *car = new Car();! ! car->body = builder->getBody();! ! car->engine = builder->getEngine();! ! car->wheels[0] = builder->getWheel();! car->wheels[1] = builder->getWheel();! car->wheels[2] = builder->getWheel();! car->wheels[3] = builder->getWheel();! ! return car;! }! };
  13. int main() {! Car car;! Director director;! ! JeepBuilder jeepBuilder;!

    NissanBuilder nissanBuilder;! ! cout << "Jeep" << endl;! director.setBuilder(&jeepBuilder);! car = director.getCar();! car->specifications();! ! cout << endl;! ! cout << "Nissan" << endl;! director.setBuilder(&nissanBuilder);! car = director.getCar();! car->specifications();! ! return 0;! }
  14. • Внутреннее представление продукта можно легко изменять (создав новый подкласс

    Builder). • Конструирование отдельно, представление отдельно. Представление (внутренняя структура) скрыта. • Тонкий контроль над процессом конструирования (Director инкапсулирует алгоритм конструирования). • У продуктов нет базового класса.
  15. FACTORY METHOD • Фабричный метод — паттерн, порождающий объекты. •

    Определяет интерфейс для создания объекта. Какой объект какого именно класса будет создан — деталь реализации (определяется подклассами). • Используется в Abstract Factory.
  16. struct Product {! virtual string getName() = 0;! };! !

    struct ConcreteProductA : Product {! string getName() { return "ConcreteProductA"; }! };! ! struct ConcreteProductB : Product {! string getName() { return "ConcreteProductB"; }! };! ! struct Creator {! virtual Product *factoryMethod() = 0;! };! ! struct ConcreteCreatorA : Creator {! Product *factoryMethod() { return new ConcreteProductA(); }! };! ! struct ConcreteCreatorB : Creator {! Product *factoryMethod() { return new ConcreteProductB(); }! };!
  17. int main() {! static const size_t count = 2;! ConcreteCreatorA

    CreatorA;! ConcreteCreatorB CreatorB;! // An array of creators! Creator* creators[count] = {&CreatorA,&CreatorB};! // Iterate over creators and create products! for (size_t i = 0; i < count; i++) {! Product *product = creators[i]->factoryMethod();! cout << product->getName() << endl;! delete product;! }! return 0;! }
  18. class Shape {! public:! virtual void draw() = 0;! !

    static Shape *create(string type);! };! ! class Circle : public Shape {! public:! void draw() { cout << "I am circle" << endl; }! };! ! class Square : public Shape {! public:! void draw() { cout << "I am square" << endl; }! };! ! Shape *Shape::create(string type) {! if (type == "circle") return new Circle();! if (type == "square") return new Square();! return 0;! } Параметризованное 
 создание объектов
  19. ! void main() {! // Give me a circle! Shape

    *obj1 = Shape::create("circle");! ! // Give me a square! Shape *obj2 = Shape::create("square");! ! obj1->draw();! obj2->draw();! ! delete obj1;! delete obj2;! }!
  20. struct Creator {! virtual Product *Create(int productId) {! if (id

    == MINE)! return new MyProduct();! if (id == YOURS)! return new YourProduct();! ! return 0;! }! };! ! struct MyCreator : Creator {! Product *Create(int productId) {! if (id == THEIRS)! return new TheirProduct();! ! return Creator::Create(productId);! }! };! Параметризованное 
 создание с наследованием
  21. • В Creator можно задать поведение по умолчанию, а можно

    и не задавать. • Параметризация: нужна, когда снаружи поступает ID или имя класса. • Factory Method + Template Method = гибкость при конструировании объекта.
  22. PROTOTYPE • Прототип — паттерн, порождающий объекты. • Вид создаваемого

    объекта задается с помощью экземпляра-прототипа. Новые объекты создаются путем копирования прототипа.
  23. Prototype ——————— clone() ConcreteProto1 ——————— clone() Client ——————— doSomething() ConcreteProto2

    ——————— clone() возвращает копию себя возвращает копию себя prototype p = prototype->clone(); …
  24. class Prototype {! std::string type;! int value;! ! public:! virtual

    Prototype *clone() = 0;! ! std::string getType() { return type; }! int getValue() { return value; }! };! ! class ConcretePrototype1 : public Prototype {! public:! ConcretePrototype1(int number) ! : type("Type1"), value(number) {! ! Prototype *clone() {! return new ConcretePrototype1(*this);! }! };! ! class ConcretePrototype2 : public Prototype {! public:! ConcretePrototype2(int number)! : type("Type2"), value(number) {! ! Prototype *clone() {! return new ConcretePrototype2(*this);! }! };
  25. class ObjectFactory {! static Prototype *type1value1;! static Prototype *type1value2;! static

    Prototype *type2value1;! static Prototype *type2value2;! ! public:! static void initialize() {! type1value1 = new ConcretePrototype1(1);! type1value2 = new ConcretePrototype1(2);! type2value1 = new ConcretePrototype2(1);! type2value2 = new ConcretePrototype2(2);! }! ! static Prototype *getType1Value1() {! return type1value1->clone();! }! ! static Prototype *getType1Value2() { ! return type1value2->clone(); ! }! ! static Prototype *getType2Value1() { ! return type2value1->clone();! }! ! static Prototype *getType2Value2() {! return type2value2->clone();! }! };! ! Prototype *ObjectFactory::type1value1 = 0;! Prototype *ObjectFactory::type1value2 = 0;! Prototype *ObjectFactory::type2value1 = 0;! Prototype *ObjectFactory::type2value2 = 0;
  26. • Главная функция — clone(). • Часто используется диспетчер прототипов

    (в примере класс ObjectFactory). • Прототипы можно создавать и удалять динамически (в отличие от классов в Factory Method). Количество классов уменьшается. • Различие поведения задается не созданием новых классов, а заданием атрибутов (значений членов). • Практически единственный способ работы при наличии кода, загружаемого динамически (DLL).