Programming Taskbook


E-mail:

Пароль:

Регистрация пользователя   Восстановление пароля

 

ЮФУ SMBU

Электронный задачник по программированию

©  М. Э. Абрамян (Южный федеральный университет, Университет МГУ-ППИ в Шэньчжэне), 1998–2024

 

PT for OOP | Группы заданий | OOP2Struc

PrevNext


Структурные паттерны

Adapter, Composite, Decorator

OOP2Struc1°.

OOPAdapterO.png

Adapter (Адаптер) — структурный паттерн.

Известен также под именем Wrapper (Обертка).

Частота использования: выше средней.

Назначение: преобразует интерфейс одного класса в интерфейс другого, который ожидают клиенты. Адаптер обеспечивает совместную работу классов с несовместимыми интерфейсами, которая без него была бы невозможна.

Участники:

• Target (Целевой класс) — определяет зависящий от предметной области интерфейс, которым пользуется Client;

• Client (Клиент) — вступает во взаимоотношения с объектами, удовлетворяющими интерфейсу Target;

• Adaptee (Адаптируемый класс) — определяет существующий интерфейс, который нуждается в адаптации;

• Adapter (Адаптер) — адаптирует интерфейс Adaptee к интерфейсу Target.

В данном задании рассматривается вариант адаптера, использующий композицию. Такой вариант называется адаптером объекта, поскольку адаптируется объект типа Adaptee, входящий в виде ссылочного поля в класс Adapter.

Задание 1. Абстрактный класс Target содержит три абстрактных метода: GetA, GetB и Request (не имеют параметров, возвращают значение целого типа). Класс ConcreteTarget является потомком класса Target; он содержит поля a и b целого типа, которые инициализируются в конструкторе, имеющем одноименные параметры. Методы GetA и GetB класса ConcreteTarget возвращают значения полей a и b соответственно, а метод Request возвращает сумму этих полей.

Класс Adaptee содержит два целочисленных поля a и b, конструктор с параметрами a и b, задающий значения этих полей, метод GetAll, возвращающий текущие значения полей (либо с помощью выходных параметров, либо с помощью возвращаемого значения — массива или кортежа), и метод SpecificRequest без параметров, возвращающий произведение полей a и b.

Реализовать класс Adapter, адаптирующий класс Adaptee к интерфейсу класса Target. Класс должен быть адаптером объекта: он порождается от класса Target и включает ссылку ad на экземпляр адаптируемого объекта Adaptee. Ссылка ad инициализируется в конструкторе класса Adapter путем вызова конструктора класса Adaptee с параметрами a и b, совпадающими с одноименными параметрами конструктора класса Adapter. Метод Request класса Adapter должен вызывать метод SpecificRequest объекта ad, а методы GetA и GetB — возвращать значения полей a и b объекта ad, используя его метод GetAll.

Тестирование разработанной системы классов. Дано целое число N (≤ 6) и набор из N троек (C, A, B), где C является символом «+» или «*», а элементы A и B являются целыми числами. Создать структуру данных (например, массив) с элементами-ссылками типа Target и заполнить ее объектами типа ConcreteTarget (для троек с символом «+») и Adapter (для троек с символом «*») с полями, равными A и B. Перебирая элементы полученного набора в обратном порядке, вывести для каждого из них значения полей a, b и результат выполнения метода Request.

[C++]

class Adaptee
{
    // Do not change the implementation of the class
    int a, b;
public:
    Adaptee(int a, int b) : a(a), b(b) {}
    void GetAll(int& a, int& b);
    int SpecificRequest();
};

void Adaptee::GetAll(int& a, int& b)
{
    a = this->a;
    b = this->b;
}
int Adaptee::SpecificRequest()
{
    return a * b;
}

class Target
{
public:
    virtual int GetA() = 0;
    virtual int GetB() = 0;
    virtual int Request() = 0;
    virtual ~Target()
    {
        Show("Target");
    }
};

// Implement the ConcreteTarget and Adapter classes

[C#]

public class Adaptee
{
    // Do not change the implementation of the class
    int a, b;
    public Adaptee(int a, int b)
    {
        this.a = a;
        this.b = b;
    }
    public void GetAll(out int a, out int b)
    {
        a = this.a;
        b = this.b;
    }
    public int SpecificRequest()
    {
        return a * b;
    }
}

public abstract class Target
{
    public abstract int GetA();
    public abstract int GetB();
    public abstract int Request();
}

// Implement the ConcreteTarget and Adapter classes

[Java]

class Adaptee {
    // Do not change the implementation of the class
    private int a,b;

    public Adaptee(int a,int b) {
        this.a = a;
        this.b = b;
    }

    public int[] getAll() {
        int res[] = {this.a,this.b};
        return res;
    }

    public int specificRequest() {
        return a * b;
    }
}

abstract class Target {
    public abstract int getA();
    public abstract int getB();
    public abstract int request();
}

// Implement the ConcreteTarget and Adapter classes

[Python]

class Adaptee:
    # Do not change the implementation of the class
    def __init__(self, a, b):
        self.__a = a
        self.__b = b

    def getAll(self):
        return self.__a, self.__b

    def specificRequest(self):
        return self.__a * self.__b


class ConcreteTarget:
    def __init__(self, a, b):
        pass
        # Implement the "constructor"

    def getA(self):
        pass
        # Implement the method

    def getB(self):
        pass
        # Implement the method

    def request(self):
        pass
        # Implement the method

# Implement the Adapter class

[Ruby]

class Adaptee
    # Do not change the implementation of the class
    def initialize(a,b)
        @a = a
        @b = b
    end

    def getAll
        return @a,@b
    end

    def specificRequest
        return @a * @b
    end
end

class ConcreteTarget
    def initialize(a,b)
        # Implement the "constructor"
    end

    def getA
        # Implement the method
    end

    def getB
        # Implement the method
    end

    def request
        # Implement the method
    end
end

# Implement the Adapter class

OOP2Struc2°.

OOPAdapterC.png

Adapter (Адаптер) — структурный паттерн.

В данном задании рассматривается вариант адаптера, использующий множественное наследование. Такой вариант называется адаптером класса, поскольку класс Adapter порождается от класса Adaptee, наследуя его реализацию (а также от класса Target, наследуя его интерфейс). Если язык не поддерживает множественное наследование, то адаптер класса можно реализовать с помощью интерфейсов; для этого надо преобразовать абстрактный класс Target в интерфейс ITarget, сделать класс Adapter потомком класса Adaptee и добавить к нему интерфейс ITarget.

Задание 2. Выполнить предыдущее задание (см. OOP2Struc1), реализовав Adapter как адаптер класса. Для языков, не поддерживающих множественное наследование, определить интерфейс ITarget с методами GetA, GetB и Request и добавить интерфейс ITarget к классам ConcreteTarget и Adapter (абстрактный класс Target теперь не требуется; для хранения исходных данных надо использовать коллекцию с элементами интерфейсного типа ITarget).

[C++]

class Adaptee
{
    // Do not change the implementation of the class
    int a, b;
public:
    Adaptee(int a, int b) : a(a), b(b) {}
    void GetAll(int& a, int& b);
    int SpecificRequest();
};

void Adaptee::GetAll(int& a, int& b)
{
    a = this->a;
    b = this->b;
}
int Adaptee::SpecificRequest()
{
    return a * b;
}

class Target
{
public:
    virtual int GetA() = 0;
    virtual int GetB() = 0;
    virtual int Request() = 0;
    virtual ~Target()
    {
        Show("Target");
    }
};

// Implement the ConcreteTarget and Adapter classes;
//   for the Adapter class, use multiple inheritance
//   (from the Target and Adaptee classes)

[C#]

public class Adaptee
{
    // Do not change the implementation of the class
    int a, b;
    public Adaptee(int a, int b)
    {
        this.a = a;
        this.b = b;
    }
    public void GetAll(out int a, out int b)
    {
        a = this.a;
        b = this.b;
    }
    public int SpecificRequest()
    {
        return a * b;
    }
}

public abstract class Target
{
    // Convert this abstract class into the ITarget interface
    public abstract int GetA();
    public abstract int GetB();
    public abstract int Request();
}

// Implement the ConcreteTarget and Adapter classes
// These classes must implement the ITarget interface;
//   the Adapter class must be a descendant of the Adaptee class

[Java]

class Adaptee {
    // Do not change the implementation of the class
    private int a,b;

    public Adaptee(int a,int b) {
        this.a = a;
        this.b = b;
    }

    public int[] getAll() {
        int res[] = {this.a,this.b};
        return res;
    }

    public int specificRequest() {
        return a * b;
    }
}

abstract class Target {
    // Convert this abstract class into the ITarget interface
    public abstract int getA();
    public abstract int getB();
    public abstract int request();
}

// Implement the ConcreteTarget and Adapter classes
// These classes must implement the ITarget interface;
//   the Adapter class must be a descendant of the Adaptee class

[Python]

class Adaptee:
    # Do not change the implementation of the class
    def __init__(self, a, b):
        self.__a = a
        self.__b = b

    def getAll(self):
        return self.__a, self.__b

    def specificRequest(self):
        return self.__a * self.__b


class ConcreteTarget:
    def __init__(self, a, b):
        pass
        # Implement the "constructor"

    def getA(self):
        pass
        # Implement the method

    def getB(self):
        pass
        # Implement the method

    def request(self):
        pass
        # Implement the method

# Implement the Adapter class;
#   the Adapter class must be
#   a descendant of the Adaptee class

[Ruby]

class Adaptee
    # Do not change the implementation of the class
    def initialize(a,b)
        @a = a
        @b = b
    end

    def getAll
        return @a,@b
    end

    def specificRequest
        return @a * @b
    end
end

class ConcreteTarget
    def initialize(a,b)
        # Implement the "constructor"
    end

    def getA
        # Implement the method
    end

    def getB
        # Implement the method
    end

    def request
        # Implement the method
    end
end

# Implement the Adapter class;
#   the Adapter class must be a descendant
#   of the Adaptee class

OOP2Struc3°. Adapter (Адаптер) — структурный паттерн.

Задание 3. Дан абстрактный класс Shape, предоставляющий интерфейс для графических объектов: метод GetInfo без параметров, возвращающий строку с именем объекта и координатами левой верхней и правой нижней вершины ограничивающего прямоугольника (считается, что ось OY направлена вниз), и метод MoveBy(a, b) с двумя целочисленными параметрами, определяющими вектор, на который надо сместить данный графический объект (метод не возвращает значений). В классе Shape методы GetInfo и MoveBy являются абстрактными.

Также дан конкретный класс RectShape — потомок класса Shape, реализующий прямоугольник и имеющий конструктор с параметрами (x1, y1, x2, y2), которые задают координаты левой верхней и правой нижней вершины этого прямоугольника. Метод GetInfo для данного класса возвращает строку вида «R(x1,y1)(x2,y2)» с текущими значениями координат (например, «R(1,−4)(3,2)»).

Дан класс TextView для работы с текстовыми объектами. Он содержит поля x, y (координаты точки привязки — левого верхнего угла текстовой области), width, height (ширина и высота текстовой области) и методы GetOrigin (возвращает координаты точки привязки), SetOrigin (изменяет точку привязки), GetSize (возвращает размеры текстовой области) и SetSize (изменяет размеры текстовой области). Методы GetOrigin и GetSize возвращают результаты либо с помощью выходных параметров, либо с помощью возвращаемого значения — массива или кортежа. Конструктор класса не имеет параметров (поля x и y полагаются равными 0, поля width и height — равными 1).

Реализовать класс TextShape, адаптирующий класс TextView к интерфейсу класса Shape. Класс должен быть адаптером объекта: он порождается от класса Shape и включает поле tview, являющееся ссылкой на экземпляр адаптируемого объекта TextView (других полей класс TextShape не содержит). Метод GetInfo класса TextShape должен возвращать строку вида «T(x1,y1)(x2,y2)» с текущими значениями левой верхней и правой нижней вершины ограничивающего прямоугольника. Включить в класс TextShape конструктор с параметрами (x1, y1, x2, y2), задающими координаты левой верхней и правой нижней вершины ограничивающего прямоугольника для текстовой области (эти параметры должны использоваться в конструкторе при инициализации поля tview).

Тестирование разработанной системы классов. Дано целое число N (≤ 8) и набор из N пятерок (C, X1, Y1, X2, Y2), где C является символом «R» или «T», а остальные элементы являются целыми числами. Кроме того, даны целые числа A и B. Создать структуру данных (например, массив) с элементами типа Shape и заполнить ее объектами типа RectShape (для пятерок с символом «R») и TextShape (для пятерок с символом «T»), используя значения X1, Y1, X2, Y2 в качестве параметров соответствующего конструктора. Применить к каждому элементу созданного набора метод MoveBy с параметрами A и B и вывести строковые представления элементов набора с помощью метода GetInfo (перебирая элементы в исходном порядке).

[C++]

class TextView
{
    // Do not change the implementation of the class
    int x = 0, y = 0;
    int width = 1, height = 1;
public:
    void GetOrigin(int& x, int& y);
    void SetOrigin(int x, int y);
    void GetSize(int& width, int& height);
    void SetSize(int width, int height);
};

void TextView::GetOrigin(int& x, int& y)
{
    x = this->x;
    y = this->y;
}
void TextView::SetOrigin(int x, int y)
{
    this->x = x;
    this->y = y;
}
void TextView::GetSize(int& width, int& height)
{
    width = this->width;
    height = this->height;
}
void TextView::SetSize(int width, int height)
{
    this->width = width;
    this->height = height;
}

class Shape
{
public:
    virtual string GetInfo() = 0;
    virtual void MoveBy(int a, int b) = 0;
    virtual ~Shape()
    {
        Show("Shape");
    }
};

// Implement the RectShape and TextShape descendant classes

[C#]

public class TextView
{
    // Do not change the implementation of the class
    int x, y;
    int width = 1, height = 1;
    public void GetOrigin(out int x, out int y)
    {
        x = this.x;
        y = this.y;
    }
    public void SetOrigin(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
    public void GetSize(out int width, out int height)
    {
        width = this.width;
        height = this.height;
    }
    public void SetSize(int width, int height)
    {
        this.width = width;
        this.height = height;
    }
}

public abstract class Shape
{
    public abstract string GetInfo();
    public abstract void MoveBy(int a, int b);
}

// Implement the RectShape and TextShape descendant classes

[Java]

class TextView {
    // Do not change the implementation of the class
    private int x = 0,y = 0;
    private int width = 1,height = 1;

    public int[] getOrigin() {
        int res[] = {this.x,this.y};
        return res;
    }

    public void setOrigin(int x,int y) {
        this.x = x;
        this.y = y;
    }

    public int[] getSize() {
        int res[] = {this.width,this.height};
        return res;
    }

    public void setSize(int width,int height) {
        this.width = width;
        this.height = height;
    }
}

abstract class Shape {
    public abstract String getInfo();
    public abstract void moveBy(int a,int b);
}

// Implement the RectShape and TextShape descendant classes

[Python]

class TextView:
    # Do not change the implementation of the class
    def __init__(self):
        self.__x = 0
        self.__y = 0
        self.__width = 1
        self.__height = 1

    def getOrigin(self):
        return [self.__x, self.__y]

    def setOrigin(self, x, y):
        self.__x = x
        self.__y = y

    def getSize(self):
        return [self.__width, self.__height]

    def setSize(self, width, height):
        self.__width = width
        self.__height = height

class RectShape:
    def __init__(self, x1, y1, x2, y2):
        pass
        # Implement the "constructor"

    def getInfo(self):
        pass
        # Implement the method

    def moveBy(self, a, b):
        pass
        # Implement the method

# Implement the TextShape class

[Ruby]

class TextView
    # Do not change the implementation of the class
    def initialize
        @x = 0
        @y = 0
        @width = 1
        @height = 1
    end

    def getOrigin
        return [@x,@y]
    end

    def setOrigin(x,y)
        @x = x
        @y = y
    end

    def getSize
        return [@width,@height]
    end

    def setSize(width,height)
        @width = width
        @height = height
    end
end

class RectShape
    def initialize(x1,y1,x2,y2)
        # Implement the "constructor"
    end

    def getInfo
        # Implement the method
    end

    def moveBy(a,b)
        # Implement the method
    end
end

# Implement the TextShape class

OOP2Struc4°. Adapter (Адаптер) — структурный паттерн.

Задание 4. Выполнить предыдущее задание (см. OOP2Struc3), реализовав TextShape как адаптер класса. Для языков, не поддерживающих множественное наследование, преобразовать абстрактный класс Shape в интерфейс IShape и добавить его к классам RectShape и TextShape (для хранения исходных данных в этом случае надо использовать коллекцию с элементами интерфейсного типа IShape).

[C++]

class TextView
{
    // Do not change the implementation of the class
    int x = 0, y = 0;
    int width = 1, height = 1;
public:
    void GetOrigin(int& x, int& y);
    void SetOrigin(int x, int y);
    void GetSize(int& width, int& height);
    void SetSize(int width, int height);
};

void TextView::GetOrigin(int& x, int& y)
{
    x = this->x;
    y = this->y;
}
void TextView::SetOrigin(int x, int y)
{
    this->x = x;
    this->y = y;
}
void TextView::GetSize(int& width, int& height)
{
    width = this->width;
    height = this->height;
}
void TextView::SetSize(int width, int height)
{
    this->width = width;
    this->height = height;
}

class Shape
{
public:
    virtual string GetInfo() = 0;
    virtual void MoveBy(int a, int b) = 0;
    virtual ~Shape()
    {
        Show("Shape");
    }
};

// Implement the RectShape and TextShape classes;
//   for the TextShape class, use multiple inheritance
//   (from the Shape and TextView classes)

[C#]

public class TextView
{
    // Do not change the implementation of the class
    int x, y;
    int width = 1, height = 1;
    public void GetOrigin(out int x, out int y)
    {
        x = this.x;
        y = this.y;
    }
    public void SetOrigin(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
    public void GetSize(out int width, out int height)
    {
        width = this.width;
        height = this.height;
    }
    public void SetSize(int width, int height)
    {
        this.width = width;
        this.height = height;
    }
}

public abstract class Shape
{
    // Convert this abstract class into the IShape interface
    public abstract string GetInfo();
    public abstract void MoveBy(int a, int b);
}

// Implement the RectShape and TextShape classes
// These classes must implement the IShape interface;
//   the TextShape class must be a descendant of the TextView class

[Java]

class TextView {
    // Do not change the implementation of the class
    private int x = 0,y = 0;
    private int width = 1,height = 1;

    public int[] getOrigin() {
        int res[] = {this.x,this.y};
        return res;
    }

    public void setOrigin(int x,int y) {
        this.x = x;
        this.y = y;
    }

    public int[] getSize() {
        int res[] = {this.width,this.height};
        return res;
    }

    public void setSize(int width,int height) {
        this.width = width;
        this.height = height;
    }
}

abstract class Shape {
    // Convert this abstract class into the IShape interface
    public abstract String getInfo();
    public abstract void moveBy(int a,int b);
}

// Implement the RectShape and TextShape classes
// These classes must implement the IShape interface;
//   the TextShape class must be a descendant of the TextView class

[Python]

class TextView:
    # Do not change the implementation of the class
    def __init__(self):
        self.__x = 0
        self.__y = 0
        self.__width = 1
        self.__height = 1

    def getOrigin(self):
        return [self.__x, self.__y]

    def setOrigin(self, x, y):
        self.__x = x
        self.__y = y

    def getSize(self):
        return [self.__width, self.__height]

    def setSize(self, width, height):
        self.__width = width
        self.__height = height

class RectShape:
    def __init__(self, x1, y1, x2, y2):
        pass
        # Implement the "constructor"

    def getInfo(self):
        pass
        # Implement the method

    def moveBy(self, a, b):
        pass
        # Implement the method

# Implement the TextShape class;
#   the TextShape class must be
#   a descendant of the TextView class

[Ruby]

class TextView
    # Do not change the implementation of the class
    def initialize
        @x = 0
        @y = 0
        @width = 1
        @height = 1
    end

    def getOrigin
        return [@x,@y]
    end

    def setOrigin(x,y)
        @x = x
        @y = y
    end

    def getSize
        return [@width,@height]
    end

    def setSize(width,height)
        @width = width
        @height = height
    end
end

class RectShape
    def initialize(x1,y1,x2,y2)
        # Implement the "constructor"
    end

    def getInfo
        # Implement the method
    end

    def moveBy(a,b)
        # Implement the method
    end
end

# Implement the TextShape class;
#   the TextShape class must be
#   a descendant of the TextView class

OOP2Struc5°.

OOPComposite.png

Composite (Компоновщик) — структурный паттерн.

Частота использования: выше средней.

Назначение: компонует объекты в древовидные структуры для представления иерархий «часть-целое». Позволяет клиентам единообразно трактовать индивидуальные и составные объекты.

Участники:

• Component (Компонент) — объявляет интерфейс для компонуемых объектов; предоставляет подходящую реализацию операций по умолчанию, общую для всех классов; объявляет интерфейс для доступа к дочерним компонентам и управления ими;

• Leaf (Лист) — представляет листовой узел композиции, не имеющий потомков;

• Composite (Составной объект) — хранит дочерние компоненты составного узла; реализует относящиеся к управлению потомками операции в интерфейсе класса Component;

• Client (Клиент) — манипулирует объектами композиции через интерфейс Component.

Объекты-листы и составные объекты могут также содержать дополнительные методы, определяющие их особое поведение, однако паттерн Composite ориентирован прежде всего на применение тех методов, которые являются общими у всех объектов композиции (хотя и реализуются по-разному для листов и составных объектов).

Задание 1. Реализовать иерархию классов, включающую абстрактный класс Component с методами AddComponent и Operation и конкретные классы Leaf и Composite. Метод AddComponent с параметром-ссылкой c типа Component добавляет компонент c в набор дочерних компонентов (имеет смысл только для класса Composite; для класса Leaf не выполняет никаких действий), метод Operation возвращает строковое представление данного компонента и всех его потомков (при наличии). В классе Component метод AddComponent не выполняет никаких действий, а метод Operation является абстрактным.

Классы Composite и Leaf содержат символьное поле data; метод Operation класса Leaf возвращает это поле (преобразованное к строковому типу), метод Operation класса Composite возвращает строку, начинающуюся с символа data, после которого стоит открывающая круглая скобка «(», затем указываются данные, полученные методом Operation для каждого дочернего компонента (без пробелов), а затем указывается закрывающая круглая скобка «)». Класс Composite хранит свои дочерние компоненты в структуре данных children (например, массиве) с элементами-ссылками типа Component (можно считать, что любой объект типа Composite содержит не более 15 дочерних компонентов). Конструктор классов Leaf и Composite содержит один символьный параметр, которым инициализируется поле data.

Тестирование разработанной системы классов. Дано целое число N (≤ 15) и набор из N символов, являющихся прописными или строчными латинскими буквами. Создать набор данных comp (например, массив) из N ссылок на объекты Component и заполнить этот набор, создавая для каждой прописной буквы из исходного набора символов объект типа Composite, а для каждой строчной буквы — объект типа Leaf, и указывая эту букву в качестве параметра конструктора объекта.

Кроме того, дан набор из N целых чисел, определяющих связи между объектами набора comp: число с индексом K (K = 0, …, N − 1) определяет индекс родительского объекта для объекта с индексом K (при этом гарантируется, что родительский объект обязательно имеет тип Composite). Если объект не имеет родителя, то соответствующий элемент в исходном наборе чисел равен −1. Если несколько объектов имеют общего родителя, то они должны добвляться к нему в порядке их следования в наборе comp. Используя данные из исходного набора чисел и вызывая метод AddComponent для требуемых объектов типа Composite, установить связи между объектами набора comp. Затем, перебирая объекты из набора comp с порядке возрастания их индексов, вызвать для каждого из них метод Operation и вывести возвращаемое этим методом строковое описание объекта.

[C++]

class Component
{
public:
    virtual void AddComponent(shared_ptr<Component> c) {}
    virtual string Operation() = 0;
    virtual ~Component()
    {
        Show("Component");
    }
};

// Implement the Leaf and Composite descendant classes

[C#]

public abstract class Component
{
    public virtual void AddComponent(Component c) {}
    public abstract string Operation();
}

// Implement the Leaf and Composite descendant classes

[Java]

abstract class Component {
    public void addComponent(Component c) {}
    public abstract String operation();
}

// Implement the Leaf and Composite descendant classes

[Python]

class Composite:
    def __init__(self, data):
        pass
        # Implement the "constructor"

    def addComponent(self, c):
        pass
        # Implement the method

    def operation(self):
        pass
        # Implement the method

# Implement the Leaf class

[Ruby]

class Composite
    def initialize(data)
        # Implement the "constructor"
    end

    def addComponent(c)
        # Implement the method
    end

    def operation
        # Implement the method
    end
end

# Implement the Leaf class

OOP2Struc6°. Composite (Компоновщик) — структурный паттерн.

Задание 2. Реализовать иерархию классов, включающую абстрактный класс Device (устройство) с методами Add, GetName и GetTotalPrice и конкретные классы SimpleDevice (простое устройство) и CompoundDevice (составное устройство). Метод Add с параметром-ссылкой d типа Device добавляет устройство d в набор дочерних устройств (имеет смысл только для класса CompoundDevice; для класса SimpleDevice не выполняет никаких действий), метод GetName возвращает строковое имя данного устройства, метод GetTotalPrice возвращает стоимость данного устройства и всех его потомков (целое число). В классе Device метод Add не выполняет никаких действий, а методы GetName и GetTotalPrice являются абстрактными.

Классы SimpleDevice и CompoundDevice содержат строковое поле name и целочисленное поле price; класс CompoundDevice хранит свои дочерние устройства в виде массива или другой структуры данных с элементами-ссылками типа Device (можно считать, что любой объект типа CompoundDevice содержит не более 15 дочерних устройств). Конструктор классов SimpleDevice и CompoundDevice содержит параметры name и price, которые используются для инициализации одноименных полей.

Тестирование разработанной системы классов. Дано целое число N (≤ 15) и N пар вида (name, price), где name — некоторая строка, а price — положительное целое число. Первый символ строки name является латинской буквой; если буква заглавная, то строка определяет составное устройство, а если строчная — простое устройство. Кроме того, дан набор из N целых чисел, определяющих связи между исходными устройствами: число с индексом K (K = 0, …, N − 1) определяет индекс родительского устройства для исходного устройства с индексом K (при этом гарантируется, что родительское устройство обязательно имеет тип CompoundDevice). Если устройство не имеет родителя, то соответствующий элемент в исходном наборе чисел равен −1. Перебирая созданные устройства в порядке, соответствующем порядку их характеристик (name, price) и используя методы GetName и GetTotalPrice, вывести для каждого устройства название и полную стоимость.

[C++]

class Device
{
public:
    virtual void Add(shared_ptr<Device> d) {}
    virtual string GetName() = 0;
    virtual int GetTotalPrice() = 0;
    virtual ~Device()
    {
        Show("Device");
    }
};

// Implement the SimpleDevice
//   and CompoundDevice descendant classes

[C#]

public abstract class Device
{
    public virtual void Add(Device d) {}
    public abstract string GetName();
    public abstract int GetTotalPrice();
}

// Implement the SimpleDevice
//   and CompoundDevice descendant classes

[Java]

abstract class Device {
    public void add(Device d) {}
    public abstract String getName();
    public abstract int getTotalPrice();
}

// Implement the SimpleDevice
//   and CompoundDevice descendant classes

[Python]

class SimpleDevice:
    def __init__(self, name, price):
        pass
        # Implement the "constructor"

    def getName(self):
        pass
        # Implement the method

    def getTotalPrice(self):
        pass
        # Implement the method

# Implement the CompoundDevice class

[Ruby]

class SimpleDevice
    def initialize(name,price)
        # Implement the "constructor"
    end

    def getName
        # Implement the method
    end

    def getTotalPrice
        # Implement the method
    end
end

# Implement the CompoundDevice class

OOP2Struc7°.

OOPDecorator.png

Decorator (Декоратор) — структурный паттерн.

Известен также под именем Wrapper (Обертка).

Частота использования: средняя.

Назначение: динамически добавляет объекту новые возможности, приводящие к изменению его состояния и/или поведения. Является гибкой альтернативой порождению подклассов с целью расширения функциональности.

Участники:

• Component (Компонент) — определяет интерфейс для объектов, к которым могут быть динамически добавлены новые возможности;

• ConcreteComponent (Конкретный компонент) — определяет объект, к которому могут быть добавлены новые возможности;

• Decorator (Декоратор) — хранит ссылку на объект Component и определяет интерфейс, соответствующий интерфейсу Component;

• ConcreteDecoratorA и ConcreteDecoratorB (Конкретные декораторы) — добавляют к компоненту новые возможности, изменяющие его состояние и/или поведение.

Задание 1. Реализовать иерархию классов, которая включает абстрактный класс Component с абстрактным методом Operation (не имеет параметров, возвращает строку), абстрактный класс Decorator, который является потомком класса Component и содержит защищенное поле comp — ссылку на объект типа Component, и конкретные классы ConcreteComponent (потомок класса Component), ConcreteDecoratorA и ConcreteDecoratorB (потомки класса Decorator).

Класс ConcreteComponent содержит строковое поле text, которое инициализируется в конструкторе с помощью одноименного параметра. Метод Operation класса ConcreteComponent возвращает строку text.

Классы ConcreteDecoratorA и ConcreteDecoratorB имеют поле comp, являющееся ссылкой на объект типа Component; класс ConcreteDecoratorA содержит также символьное поле ch. В конструкторах классов ConcreteDecoratorA и ConcreteDecoratorB поля инициализируются с помощью одноименных параметров.

Метод Operation конкретного декоратора A возвращает строку, полученную путем добавления символа ch перед и после текста, возвращенного методом Operation объекта comp. Метод Operation конкретного декоратора B возвращает строку, полученную путем добавления символа «(» перед текстом, возвращенным методом Operation объекта comp, и символа «)» после этого текста. Таким образом, каждый декоратор изменяет поведение метода Operation исходного объекта Component, добавляя к возвращаемому значению дополнительный префикс и суффикс; при этом декоратор A корректирует состояние исходного объекта, путем добавления к нему поля ch.

Тестирование разработанной системы классов. Дан символ C, целое число N (≤ 9) и N пар строк (SD), причем строка S является непустой, а строка D содержит только буквы «A» и «B» и может быть пустой. Создать набор из N объектов типа Component, формируя каждый элемент этого набора на основе соответствующей пары строк (SD) следующим образом: вначале создать объект типа ConcreteComponent, вызвав его конструктор с параметром S, а затем последовательно применять к результирующему объекту декораторы A или В, причем количество и порядок декораторов определяется строкой D (например, в случае строки «AAB» к исходному объекту типа ConcreteComponent надо последовательно применить декораторы A, A и B). В качестве второго параметра конструктора всех декораторов A использовать исходный символ C.

Перебирая созданный набор из N объектов в обратном порядке, вызвать для каждого из них метод Operation и вывести его возвращаемое значение.

[C++]

class Component
{
public:
    virtual string Operation() = 0;
    virtual ~Component()
    {
        Show("Component");
    }
};

// Implement the ConcreteComponent descendant class

class Decorator : public Component
{
protected:
    shared_ptr<Component> comp;
public:
    ~Decorator() override
    {
        Show("Decorator");
    }
};

// Implement the ConcreteDecoratorA
//   and ConcreteDecoratorB descendant classes

[C#]

public abstract class Component
{
    public abstract string Operation();
}

// Implement the ConcreteComponent descendant class

public abstract class Decorator : Component
{
    protected Component comp;
}

// Implement the ConcreteDecoratorA
//   and ConcreteDecoratorB descendant classes

[Java]

abstract class Component {
    public abstract String operation();
}

// Implement the ConcreteComponent descendant class

abstract class Decorator extends Component {
    protected Component comp;
}

// Implement the ConcreteDecoratorA
//   and ConcreteDecoratorB descendant classes

[Python]

class ConcreteComponent:
    def __init__(self, text):
        pass
        # Implement the "constructor"

    def operation(self):
        pass
        # Implement the method

class ConcreteDecoratorA:
    def __init__(self, comp, ch):
        pass
        # Implement the "constructor"

    def operation(self):
        pass
        # Implement the method

# Implement the ConcreteDecoratorB class

[Ruby]

class ConcreteComponent
    def initialize(text)
        # Implement the "constructor"
    end

    def operation
        # Implement the method
    end
end

class ConcreteDecoratorA
    def initialize(comp, ch)
        # Implement the "constructor"
    end

    def operation
        # Implement the method
    end
end

# Implement the ConcreteDecoratorB class

OOP2Struc8°. Decorator (Декоратор) — структурный паттерн.

Задание 2. Реализовать иерархию классов, включающую абстрактный класс Function с абстрактными методами GetName (без параметров; возвращает строку) и GetValue(x) (с целочисленным параметром; возвращает целое число) и пять конкретных классов — потомков Function: FX, FDouble, FTriple, FSquare, FCube.

Класс FX не имеет полей; его метод GetName возвращает строку «X», а функция GetValue(x) возвращает свой параметр x. Остальные конкретные классы являются декораторами; все они содержат ссылочное поле f типа Function и конструктор с параметром-ссылкой f типа Function, который инициализирует это поле. Метод GetName данных классов вызывает метод GetName класса f и возвращает его результат, снабженный дополнительным префиксом и суффиксом: «2*(» и «)» для FDouble, «3*(» и «)» для FTriple, «(» и «)^2» для FSquare, «(» и «)^3» для FCube. Метод GetValue(x) данных классов вызывает метод GetValue(x) класса f и возвращает его результат, преобразованный следующим образом: результат умножается на 2 для FDouble, умножается на 3 для FTriple, возводится в квадрат для FSquare, возводится в куб для FCube.

Тестирование разработанной системы классов. Дано целое число N (≤ 10) и набор из N строк; каждая строка содержит комбинацию из букв «D», «T», «S» и «C» и может быть пустой. Кроме того, даны два целых числа X1 и X2. Создать набор из N объектов типа Function, формируя каждый элемент следующим образом: вначале создать объект типа FX, а затем последовательно применять к результирующему объекту декораторы FDouble, FTriple, FSquare, FCube, причем количество и порядок декораторов определяется символами соответствующей строки из исходного набора (например, в случае строки «TCSS» к исходному объекту типа FX надо последовательно применить декораторы FTriple, FCube и два декоратора FSquare). Перебирая созданный набор из N объектов в исходном порядке, вызвать для каждого из них метод GetName, метод GetValue с параметром X1, метод GetValue с параметром X2 и вывести их возвращаемые значения.

[C++]

class Function
{
public:
    virtual string GetName() = 0;
    virtual int GetValue(int x) = 0;
    virtual ~Function()
    {
        Show("Function");
    }
};

// Implement the FX, FDouble, FTriple, FSquare
//   and FCube descendant classes

[C#]

public abstract class Function
{
    public abstract string GetName();
    public abstract int GetValue(int x);
}

// Implement the FX, FDouble, FTriple, FSquare
//   and FCube descendant classes

[Java]

abstract class Function {
    public abstract String getName();
    public abstract int getValue(int x);
}

// Implement the FX, FDouble, FTriple, FSquare
//   and FCube descendant classes

[Python]

class FX:
    def getName(self):
        pass
        # Implement the method

    def getValue(self, x):
        pass
        # Implement the method

# Implement the FDouble, FTriple, FSquare
#   and FCube classes

[Ruby]

class FX
    def getName
        # Implement the method
    end

    def getValue(x)
        # Implement the method
    end
end

# Implement the FDouble, FTriple, FSquare
#   and FCube classes

Proxy, Bridge, Flyweight

OOP2Struc9°.

OOPProxy.png

Proxy (Заместитель) — структурный паттерн.

Известен также под именем Surrogate (Суррогат).

Частота использования: выше средней.

Назначение: является суррогатом другого объекта и контролирует доступ к нему.

Участники:

• Subject (Субъект) — определяет общий для RealSubject и Proxy интерфейс, так что класс Proxy можно использовать везде, где ожидается RealSubject;

• RealSubject (Реальный субъект) — определяет реальный объект, представленный заместителем;

• Proxy (Заместитель) — хранит ссылку, которая позволяет заместителю обратиться к реальному субъекту; контролирует доступ к реальному субъекту и может отвечать за его создание и удаление; прочие обязанности зависят от вида заместителя (удаленный заместитель отвечает за отправление запроса реальному субъекту в другом адресном пространстве; виртуальный заместитель может отложить создание реального субъекта и вызывать некоторые его методы самостоятельно; защищающий заместитель проверяет, имеет ли вызывающий объект необходимые для выполнения запроса права; кэширующий заместитель обеспечивает временное хранение результатов ранее выполненных высокозатратных запросов и совместный доступ к этим результатам; имеются и другие виды заместителей).

Задание 1. Реализовать иерархию классов, включающую абстрактный класс Subject с абстрактными методами RequestA, RequestB, RequestC, RequestD и конкретные классы RealSubject и Proxy — потомки класса Subject. Указанные методы не имеют параметров и возвращают строку. Класс RealSubject не имеет полей, его методы возвращают строки «A (Real)», «B (Real)», «C (Real)», «D (Real)».

Класс Proxy является заместителем класса RealSubject, комбинирующим черты виртуального и защищающего заместителя. Предполагается, что запросы A и B являются простыми и могут быть реализованы в самом заместителе, в то время как запросы C и D являются сложными и доступны только в классе RealSubject. Кроме того, запросы A и C являются безопасными, а запросы B и D — потенциально опасными, и в некоторых ситуациях их целесообразно заблокировать. Поэтому класс Proxy содержит два логических поля: deferredMode (отложенный режим) и protectedMode (защищенный режим), которые задаются в его конструкторе с помощью одноименных параметров и определяют его поведение по отношению к реальному субъекту. Кроме того, класс Proxy содержит поле rsubj — ссылку на объект типа RealSubject.

Если поле deferredMode равно False, то объект RealSubject создается в конструкторе класса Proxy (и связывается со ссылкой rsubj), если deferredMode равно True, то начальное значение ссылки rsubj является пустым. Если поле protectedMode равно False и при этом ссылка rsubj не является пустой, то все запросы переадресуются объекту, на который ссылается rsubj. Если protectedMode равно False, а ссылка rsubj является пустой, то простые запросы A и B выполняются самим объектом Proxy и при этом возвращаются строки «A (Proxy)» и «B (Proxy)», а в случае вызова запроса C или D объект RealSubject создается и связывается со ссылкой rsubj, после чего этот запрос переадресуется ему. Если protectedMode равно True, то выполнение запросов A и C не отличается от ранее описанного, а при попытке вызова запросов B и D они отменяются (независимо от значения ссылки rsubj), причем соответствующие методы возвращают строки «B denied» и «D denied».

Тестирование разработанной системы классов. Дан набор из трех целых чисел, принимающих значения от −1 до 3, и строка, содержащая только символы «A», «B», «C», «D» — имена запросов. Создать массив из трех ссылочных элементов типа Subject, инициализировав элементы конкретными объектами в зависимости от значения исходных чисел: −1 — RealSubject, 0 — Proxy(False, False), 1 — Proxy(True, False), 2 — Proxy(False, True), 3 — Proxy(True, True). Для каждого из созданных объектов выполнить набор запросов, определяемый исходной строкой, и вывести результат, возвращаемый каждым запросом.

[C++]

class Subject
{
public:
    virtual string RequestA() = 0;
    virtual string RequestB() = 0;
    virtual string RequestC() = 0;
    virtual string RequestD() = 0;
    virtual ~Subject()
    {
        Show("Subject");
    }
};

// Implement the RealSubject and Proxy descendant classes

[C#]

public abstract class Subject
{
    public abstract string RequestA();
    public abstract string RequestB();
    public abstract string RequestC();
    public abstract string RequestD();
}

// Implement the RealSubject and Proxy descendant classes

[Java]

abstract class Subject {
    public abstract String requestA();
    public abstract String requestB();
    public abstract String requestC();
    public abstract String requestD();
}

// Implement the RealSubject and Proxy descendant classes

[Python]

class RealSubject:
    def requestA(self):
        pass
        # Implement the method

    def requestB(self):
        pass
        # Implement the method

    def requestC(self):
        pass
        # Implement the method

    def requestD(self):
        pass
        # Implement the method

# Implement the Proxy class

[Ruby]

class RealSubject
    def requestA
        # Implement the method
    end

    def requestB
        # Implement the method
    end

    def requestC
        # Implement the method
    end

    def requestD
        # Implement the method
    end
end

# Implement the Proxy class

OOP2Struc10°.

OOPBridge.png

Bridge (Мост) — структурный паттерн.

Известен также под именем Handle/Body (Описатель/Тело).

Частота использования: средняя.

Назначение: отделяет абстракцию от ее реализации так, чтобы то и другое можно было изменять независимо.

Участники:

• Abstraction (Абстракция) — определяет интерфейс абстракции; хранит ссылку на объект типа Implementor;

• RefinedAbstraction (Уточненная абстракция) — расширяет интерфейс, определенный абстракцией Abstraction;

• Implementor (Реализатор) — определяет интерфейс для классов реализации; не обязан точно соответствовать интерфейсу класса Abstraction (обычно предоставляет только примитивные операции, в то время как класс Abstraction определяет операции более высокого уровня, базирующиеся на этих примитивах);

• ConcreteImplementorA и ConcreteImplementorB (Конкретные реализаторы) — содержат конкретную реализацию интерфейса класса Implementor.

Задание 1. Реализовать иерархию классов-реализаторов, содержащую абстрактного реализатора Implementor и два конкретных реализатора ConcreteImplementorA и ConcreteImplementorB. Классы отвечают за представление горизонтальных линий и текста и включают методы DrawLine(size) и DrawText(text) (аналоги метода OperationImp на диаграмме классов), которые возвращают строковые значения. Параметр size определяет размер линии (в символах), параметр text — выводимый текст. В классе Implementor методы DrawLine и DrawText являются абстрактными. Конкретный реализатор A представляет линию в виде набора символов «−», а текст отображает в нижнем регистре. Конкретный реализатор B представляет линию в виде набора символов «=», а текст отображает в верхнем регистре. Оба конкретных реализатора имеют конструкторы без параметров, не выполняющие дополнительных действий.

Реализовать класс Abstraction, предназначенный для отображения и корректировки строки заголовка. Конструктор класса принимает параметры imp типа Implementor (ссылку на используемый реализатор) и size целого типа (размер заголовка). Класс также содержит метод Show без параметров (аналог метода Operation на диаграмме классов), возвращающий строку-заголовок, и метод SetSize(n), задающий размер заголовка равным значению n (целое неотрицательное число). Класс Abstraction реализует простейший вариант заголовка, представляющий собой линию указанного размера.

Реализовать класс RefinedAbstraction, который является усовершенствованным вариантом класса Abstraction и позволяет включать в заголовок текст. Конструктор класса RefinedAbstraction содержит, кроме параметров imp и size, имеющих тот же смысл, что и для конструктора класса Abstraction, строковый параметр caption. Заголовок формируется следующим образом: вначале указывается линия размера 1, затем строка caption, затем линия такого размера, чтобы суммарный размер заголовка был равен size. Для малых значений size строка caption может урезаться справа. Переопределить нужным образом метод Show в классе RefinedAbstraction.

Тестирование разработанной системы классов. Дано целое положительное число size (начальный размер заголовка) и строка caption (необязательный элемент заголовка). Также даны пять целых положительных чисел (новые размеры заголовков). Создать экземпляры классов Abstraction и RefinedAbstraction с указанными параметрами и каждым из конкретных реализаторов A и B и вывести соответствующие заголовки методом Show. Затем, используя каждый из новых размеров, изменить размер каждого заголовка и вывести измененные заголовки. Порядок вывода заголовков для каждого размера: Abstraction с реализатором A, Abstraction с реализатором B, RefinedAbstraction с реализатором A, RefinedAbstraction с реализатором B. Для хранения созданных объектов использовать массив из четырех ссылочных элементов типа Abstraction.

[C++]

class Implementor
{
public:
    virtual string DrawLine(int size) = 0;
    virtual string DrawText(string text) = 0;
    virtual ~Implementor()
    {
        Show("Implementor");
    }
};

// Implement the ConcreteImplementorA
//   and ConcreteImplementorB descendant classes

class Abstraction
{
protected:
    int size;
    shared_ptr<Implementor> imp;
public:
    Abstraction(shared_ptr<Implementor> imp, int size) :
        imp(imp), size(size) {}
    virtual ~Abstraction()
    {
        Show("Abstraction");
    }
    // Complete the implementation of the class Abstraction
};

// Implement the RefinedAbstraction descendant class

[C#]

public abstract class Implementor
{
    public abstract string DrawLine(int size);
    public abstract string DrawText(string text);
}

// Implement the ConcreteImplementorA
//   and ConcreteImplementorB descendant classes

public class Abstraction
{
    protected int size;
    protected Implementor imp;
    public Abstraction(Implementor imp, int size)
    {
        this.imp = imp;
        this.size = size;
    }
    // Complete the implementation of the class
}

// Implement the RefinedAbstraction descendant class

[Java]

abstract class Implementor {
    public abstract String drawLine(int size);
    public abstract String drawText(String text);
}

// Implement the ConcreteImplementorA
//   and ConcreteImplementorB descendant classes

class Abstraction {
    protected int size;
    protected Implementor imp;

    public Abstraction(Implementor imp,int size) {
        this.imp = imp;
        this.size = size;
    }
    // Complete the implementation of the class
}

// Implement the RefinedAbstraction descendant class

[Python]

class ConcreteImplementorA:
    def drawLine(self, size):
        pass
        # Implement the method

    def drawText(self, text):
        pass
        # Implement the method

# Implement the ConcreteImplementorB class

class Abstraction:
    def __init__(self, imp, size):
        self.__imp = imp
        self.__size = size

    # Complete the implementation of the class

# Implement the RefinedAbstraction descendant class

[Ruby]

class ConcreteImplementorA
    def drawLine(size)
        # Implement the method
    end

    def drawText(text)
        # Implement the method
    end
end

# Implement the ConcreteImplementorB class

class Abstraction
    def initialize(imp,size)
        @imp = imp
        @size = size
    end
    # Complete the implementation of the class
end

# Implement the RefinedAbstraction descendant class

OOP2Struc11°.

OOPFlyweight.png

Flyweight (Приспособленец) — структурный паттерн.

Частота использования: низкая.

Назначение: применяет разделение (т. е. совместное использование одного и того же экземпляра) для эффективной поддержки множества объектов, сохраняя основную часть их состояния во внешних данных клиента.

Участники:

• Flyweight (Приспособленец) — объявляет интерфейс, с помощью которого приспособленцы могут получать внешнее состояние или воздействовать на него;

• ConcreteFlyweight (Конкретный приспособленец) — реализует интерфейс класса Flyweight и добавляет при необходимости внутреннее состояние (объект класса ConcreteFlyweight должен быть разделяемым, любое сохраняемое им состояние должно быть внутренним, то есть не зависящим от контекста);

• UnsharedConcreteFlyweight (Неразделяемый конкретный приспособленец) — реализует интерфейс класса Flyweight, но не является разделяемым; данный класс может сохранять состояние, зависящее от контекста;

• FlyweightFactory (Фабрика приспособленцев) — создает объекты-приспособленцы и управляет ими; при запросе клиентом приспособленца объект FlyweightFactory предоставляет существующий экземпляр или создает новый, если готового еще нет;

• Client (Клиент) — хранит ссылки на одного или нескольких приспособленцев; вычисляет или хранит внешнее состояние приспособленцев.

Задание 1. Реализовать иерархию классов, которая включает абстрактный класс Flyweight с абстрактным методом Operation(state), который имеет логический параметр state и возвращает символьное значение, и конкретные классы ConcreteFlyweight и UnsharedConcreteFlyweight — потомки класса Flyweight. Предполагается, что клиент будет использовать большое количество объектов класса ConcreteFlyweight, поэтому этот класс должен поддерживать разделение. Метод Operation(state) класса ConcreteFlyweight возвращает символ «A», регистр которого зависит от значения state (если state равен True, то используется верхний регистр, если state равен False, то нижний). Конструктор класса ConcreteFlyweight не имеет параметров и не выполняет дополнительных действий.

Класс UnsharedConcreteFlyweight не является разделяемым; он хранит дополнительное символьное поле inf, которое инициализируется в конструкторе, имеющем соответствующий символьный параметр. Метод Operation(state) класса UnsharedConcreteFlyweight возвращает символ inf, его регистр определяется параметром state (как в методе Operation класса ConcreteFlyweight).

Реализовать класс-фабрику FlyweightFactory, содержащий поле-ссылку cf типа ConcreteFlyweight и поле count целого типа, а также конструктор без параметров (при создании данного объекта поле cf содержит пустую ссылку, а поле count — значение 0). Класс содержит метод GetFlyweight(inf) с символьным параметром и возвращаемым значением-ссылкой типа Flyweight. Если параметр отличен от символа «A» или «a», то фабрика создает и возвращает новый объект типа UnsharedConcreteFlyweight, используя конструктор с параметром inf. Если параметр представляет собой символ «A» или «a», то в случае, если поле cf содержит ссылку на существующий объект типа ConcreteFlyweight, возвращается этот объект, если же поле cf является пустым, то объект типа ConcreteFlyweight создается, сохраняется в поле cf и возвращается методом GetFlyweight. Если в методе GetFlyweight создается новый объект, то поле count увеличивается на 1; таким образом, данное поле хранит общее количество созданных объектов. Значение поля count можно получить с помощью метода GetCount без параметров.

Реализовать также класс Client, предназначенный для создания, хранения и обработки наборов объектов типа Flyweight. Класс содержит поля f — объект типа FlyweightFactory и fw — структуру ссылочных данных (например, массив) с элементами типа Flyweight (можно считать, что число элементов fw не превосходит 30). Конструктор класса Client не имеет параметров, в нем создается объект f и инициализируется структура данных fw. Класс содержит методы MakeFlyweights(inf), ShowFlyweights(state) и GetFlyweightCount. Параметр inf метода MakeFlyweights является строкой, определяющей набор создаваемых объектов типа Flyweight (для создания требуемого набора в методе MakeFlyweights в цикле вызывается метод GetFlyweight объекта f с параметром — очередным символом строки inf). Ссылки на созданные объекты сохраняются в структуре fw; при каждом вызове метода MakeFlyweights прежнее содержимое структуры fw очищается. Метод ShowFlyweights(state) возвращает строку, состоящую из символов, возвращаемых методом Operation(state) для каждого элемента структуры данных fw. Метод GetFlyweightCount без параметров возвращает количество объектов, созданных к данному моменту фабрикой f; для этого используется ее метод GetCount.

Тестирование разработанной системы классов. Даны пять текстовых строк; длина каждой строки не превосходит 30, большинство символов в этих строках являются символами «A» в верхнем или нижнем регистре. Создать объект типа Client и для каждой исходной строки s вызвать метод MakeFlyweights(s) и вывести значения, возвращаемые методами ShowFlyweights(True), ShowFlyweights(False) и GetFlyweightCount.

[C++]

class Flyweight
{
public:
    virtual char Operation(bool state) = 0;
    virtual ~Flyweight()
    {
        Show("Flyweight");
    }
};

// Implement the ConcreteFlyweight
//   and UnsharedConcreteFlyweight descendant classes

// Implement the FlyweightFactory and Client classes

[C#]

public abstract class Flyweight
{
    public abstract char Operation(bool state);
}

// Implement the ConcreteFlyweight
//   and UnsharedConcreteFlyweight descendant classes

// Implement the FlyweightFactory and Client classes

[Java]

abstract class Flyweight {
    public abstract char operation(boolean state);
}

// Implement the ConcreteFlyweight
//   and UnsharedConcreteFlyweight descendant classes

// Implement the FlyweightFactory and Client classes

[Python]

class ConcreteFlyweight:
    def operation(self, state):
        pass
        # Implement the method

# Implement the UnsharedConcreteFlyweight class

# Implement the FlyweightFactory and Client classes

[Ruby]

class ConcreteFlyweight
    def operation(state)
        # Implement the method
    end
end

# Implement the UnsharedConcreteFlyweight class

# Implement the FlyweightFactory and Client classes

PrevNext

 

Рейтинг@Mail.ru

Разработка сайта:
М. Э. Абрамян, В. Н. Брагилевский

Последнее обновление:
01.01.2024