|
© 2025
Александр Легалов
Содержание
Шаг седьмой. Добавление в мультиметод новой альтернативы
В принципе альтернатива уже была реализована на втором шаге. Поэтому стоит вопрос совместного расширения, связанного с подключением ее, когда реализован мультиметод.
Добавление альтернативы в мультиметод при процедурном подходе
Третья альтернатива и функции, осуществляющие ее обработку повторно используются из программы, реализованной на втором шаге. Также оттуда берутся обобщенная фигура и ее функции. Остается только дописать код в мультиметод, который расширяется за счет комбинаций круга с уже реализованными прямоугольником и треугольником.
// multmethod.c
// Обработчик специализации для прямоугольника и круга
void MMRC(Rectangle* r1, Circle* c2, FILE* ofst) {
fprintf(ofst, "Rectangle - Circle Combination\n");
}
// Обработчик специализации для треугольника и круга
void MMTC(Triangle* t1, Circle* c2, FILE* ofst) {
fprintf(ofst, "Triangle - Circle Combination\n");
}
// Обработчик специализации для круга и прямоугольника
void MMCR(Circle* c1, Rectangle* r2, FILE* ofst) {
fprintf(ofst, "Circle - Rectangle Combination\n");
}
// Обработчик специализации для круга и треугольника
void MMCT(Circle* c1, Triangle* t2, FILE* ofst) {
fprintf(ofst, "Circle - Triangle Combination\n");
}
// Обработчик специализации для двух кругов
void MMCC(Circle* c1, Circle* c2, FILE* ofst) {
fprintf(ofst, "Circle - Triangle Combination\n");
}
//------------------------------------------------------------------------------
void Multimethod(Figure* f1, Figure* f2, FILE* ofst) {
switch(f1->k) {
case RECTANGLE:
switch(f2->k) {
case RECTANGLE:
MMRR((Rectangle*)f1, (Rectangle*)f2, ofst);
break;
case TRIANGLE:
MMRT((Rectangle*)f1, (Triangle*)f2, ofst);
break;
case CIRCLE:
MMRC((Rectangle*)f1, (Circle*)f2, ofst);
break;
default:
fprintf(ofst,
"1st is RECTANGLE. Incorrect key of figure 2 = %d\n", f2->k);
}
break;
case TRIANGLE:
switch(f2->k) {
case RECTANGLE:
MMTR((Triangle*)f1, (Rectangle*)f2, ofst);
break;
case TRIANGLE:
MMTT((Triangle*)f1, (Triangle*)f2, ofst);
break;
case CIRCLE:
MMTC((Triangle*)f1, (Circle*)f2, ofst);
break;
default:
fprintf(ofst,
"1st is TRIANGLE. Incorrect key of figure 2 = %d\n", f2->k);
}
break;
case CIRCLE:
switch(f2->k) {
case RECTANGLE:
MMCR((Circle*)f1, (Rectangle*)f2, ofst);
break;
case TRIANGLE:
MMCT((Circle*)f1, (Triangle*)f2, ofst);
break;
case CIRCLE:
MMCC((Circle*)f1, (Circle*)f2, ofst);
break;
default:
fprintf(ofst,
"1st is CIRCLE. Incorrect key of figure 2 = %d\n", f2->k);
}
break;
default:
fprintf(ofst, "Incorrect key of figure 1 = %d\n", f1->k);
}
}
Вызов мультиметода при обходе контейнера и клиентский код используются из предшествующего шага.
В представленной схеме отдельным цветов выделены артефакты, демонстрирующие добавление ранее сформированной альтернативы. Добавляются функции, реализующие дополнительные отношения между ранее отсутствующими комбинациями альтернативных аргументов и изменяется функция, реализующая анализ альтернатив в самом мультиметоде.
Добавление альтернативы в мультиметод при ОО подходе
Прямое расширение мультиметода в связи с появлением еще одной альтернативы снова ведет к изменению интерфейсов фигур. В каждую из них, включая и обобщенную фигуру, добавляются промежуточные методы, учитывающие появление круга. При этом реализация методов круга, как и в случае процедурной программы, может быть заимствована из второго шага.
// figura.h - rласс, обобщающающий все фигуры.
class Figure {
public:
// идентификация, порождение и ввод фигуры из потока
virtual void In(std::ifstream &ifst) = 0; // ввод
virtual void Out(std::ofstream &ofst) = 0; // вывод
virtual void Out() = 0; // вывод
virtual std::string Multimethod(Figure& fig2) = 0; // мультиметод
virtual std::string FirstRectangle(Rectangle& rect) = 0;
virtual std::string FirstTriangle(Triangle& trian) = 0;
virtual std::string FirstCircle(Circle& circ) = 0;
};
// rectangle.h - прямоугольник
class Rectangle: public Figure {
int x, y; // ширина, высота
public:
// переопределяем интерфейс класса
virtual void In(std::ifstream &ifst); // ввод
virtual void Out(std::ofstream &ofst); // вывод
virtual std::string Multimethod(Figure& fig2); // мультиметод
virtual std::string FirstRectangle(Rectangle& rect);
virtual std::string FirstTriangle(Triangle& trian);
virtual std::string FirstCircle(Circle& circ);
Rectangle(): x{0}, y{0} {} // создание без инициализации.
};
// triangle.h -треугольник
class Triangle: public Figure {
int a, b, c; // стороны
public:
// переопределяем интерфейс класса
void In(std::ifstream &ifst); // ввод
virtual void Out(std::ofstream &ofst); // вывод
virtual std::string Multimethod(Figure& fig2); // мультиметод
virtual std::string FirstRectangle(Rectangle& rect);
virtual std::string FirstTriangle(Triangle& trian);
virtual std::string FirstCircle(Circle& circ);
Triangle(): a{0}, b{0}, c{0} {} // создание без инициализации.
};
// circle.h - круг
class Circle: public Figure {
int r; // радиус
public:
// переопределяем интерфейс класса
void In(std::ifstream &ifst); // ввод данных из потока
virtual void Out(std::ofstream &ofst); // вывод
virtual std::string Multimethod(Figure& fig2); // мультиметод
virtual std::string FirstRectangle(Rectangle& rect);
virtual std::string FirstTriangle(Triangle& trian);
virtual std::string FirstCircle(Circle& circ);
Circle(): r{0} {} // создание без инициализации.
};
Реализации новых комбинаций фигур, связанные с появлением круга, могут быть добавлены в новой единице компиляции, не меняя ранее написанный код.
// multimethod-new-spec.cpp
// Обработчик круга и прямоугольника
std::string Rectangle::FirstCircle(Circle& circle) {
return "Circle - Rectangle Combination\n";
}
// Обработчик круга и треугольника
std::string Triangle::FirstCircle(Circle& circle) {
return "Circle - Triangle Combination\n";
}
// Мультиметод, определяющий вход в круг
std::string Circle::Multimethod(Figure& fig2) {
return fig2.FirstCircle(reinterpret_cast<Circle&>(*this));
}
std::string Circle::FirstRectangle(Rectangle& rect) {
return "Rectangle - Circle Combination\n";
}
std::string Circle::FirstTriangle(Triangle& trian) {
return "Triangle - Circle Combination\n";
}
std::string Circle::FirstCircle(Circle& circle) {
return "Circle - Circle Combination\n";
}
Как и в случае добавления только мультиметода, расширение мультиметода при появлении новой альтернативы ведет к изменению интерфейсов классов. Реализации методов либо повторно используются из предыдущих решений, либо расширяют код в новых единицах компиляции, обеспечивая в последнем случае формирование ранее отсутствующих комбинаций полиморфных аргументов. Эти изменения отражены в схеме.
Добавление альтернативы в мультиметод при ПП подходе
В случае процедурно-параметрического подхода почти все уже написано. Остается только дописать недостающие комбинации в мультиметод, связанные с добавлением круга, и собрать проект из ранее сформированных исходных текстов. Недостающие комбинации пар учитывают появление круга.
// Обработчик специализации для прямоугольника и круга
void Multimethod<Figure.rect* r1, Figure.circ* c2>(FILE* ofst) {
fprintf(ofst, "Rectangle - Circle Combination\n");
}
// Обработчик специализации для треугольника и круга
void Multimethod<Figure.trian* r1, Figure.circ* c2>(FILE* ofst) {
fprintf(ofst, "Triangle - Circle Combination\n");
}
// Обработчик специализации для круга и прямоугольника
void Multimethod<Figure.circ* c1, Figure.rect* r2>(FILE* ofst) {
fprintf(ofst, "Circle - Rectangle Combination\n");
}
// Обработчик специализации для круга и треугольника
void Multimethod<Figure.circ* c1, Figure.trian* t2>(FILE* ofst) {
fprintf(ofst, "Circle - Triangle Combination\n");
}
// Обработчик специализации для двух кругов
void Multimethod<Figure.circ* c1, Figure.circ* c2>(FILE* ofst) {
fprintf(ofst, "Circle - Circle Combination\n");
}
Использование старых артефактов и добавление необходимых обработчиков специализаций отражено на схеме.
Выводы
Расширение мультиметода при добавлении новой альтернативы требует изменения его централизованной реализации при процедурном подходе и модификации классов в случае ОО стиля. При использовании процедурно-параметрической парадигмы нужно только добавить недостающие обработчики альтернатив.
Содержание
|