Паттерн шаблонного метода: изменение архитектуры алгоритма

Я использую шаблон метода шаблона в своем проекте, например, следующий

class Template
{
public:
void algorithm();
{
    A();
    B();
}
private:
virtual void A()=0;
virtual void B()=0;
}

У меня есть несколько подклассов, реализующих методы A и B по-разному.
Но теперь мне нужен новый класс Template2, чтобы реализовать немного другой алгоритм.

class Template2
{
public:
void algorithm();
{
    A();
    B();
    C();
}
private:
virtual void A()=0;
virtual void B()=0;
void C()
{
    //some stuff
    A();
    //some stuff
    B();
}
}

C идентичен во всех подклассах, поэтому я не делаю его виртуальным.
Прямо сейчас я создаю новую иерархию наследования на основе Template2, но это кажется глупым, потому что Мне нужно скопировать и вставить код каждого подкласса в эту новую иерархию.
Можно ли сделать это более элегантным способом?

РЕДАКТИРОВАНИЕ
Извините, я не совсем ясно выразился.
Теперь у меня есть две иерархии наследования.
1. Абстрактный класс Template и несколько подклассов A1,A2,A3,A4...
2. Абстрактный класс Template2 и несколько подклассов B1,B2,B3,B4...
Это работает нормально, но мне интересно, есть ли способ каким-то образом объединить эти две иерархии, потому что A1 и B1 имеют один и тот же код, за исключением того, что они получены из Template и Template2 соответственно.
Является ли решение шаблоном метода шаблона, для меня не имеет значения
Оба ответа bcperth и Spotted работают для меня :)
Большое спасибо.


person LtChang    schedule 01.10.2018    source источник


Ответы (2)


Я согласен с Spotted, но не думали ли вы просто добавить дополнительные алгоритмы в свой класс template? Это все еще шаблон шаблона с несколькими алгоритмами. Вы получаете более толстый класс, но без повторения кода. Ниже приведена иллюстрация.

#include <iostream>

using namespace std;

class Template
{
public:
    void algorithm1()
    {
        A();
        B();
    }

    void algorithm2()
    {
        A();
        B();
        C();
    }

private: void C()
    {
    cout << endl << "start C() ";
    A();
    cout << "middle C() ";
    B();
    cout << "end C()" << endl;
    }

private:
    virtual void A() = 0;
    virtual void B() = 0;
};

class real :public Template {

    void A() { cout << "A(1)  "; }
    void B() { cout << "B(1) "; }
};

int main()
{
    real Real;
    cout << "algorithm1" <<endl;
    Real.algorithm1();
    cout << endl;
    cout << endl << "algorithm2 << endl";
    Real.algorithm2();

    return 0;
}
person bcperth    schedule 02.10.2018
comment
Фактически, использование класса Template, предложенного здесь (с обоими алгоритмами внутри), может быть лучшим путем. - person Spotted; 02.10.2018
comment
Это действительно полезно, я думаю, что я собираюсь использовать его. - person LtChang; 02.10.2018
comment
Ок, отлично! Вы можете закрыть вопрос, нажав на галочку под стрелками вверх-вниз в левом верхнем углу моего ответа. Это вовсе не обязательно, но полезно для статистики :-) - person bcperth; 02.10.2018

Во-первых, простите мой плохой синтаксис C++.

Я предлагаю вам отделить A() и B() от Template, чтобы вам было легче повторно использовать их в Template2.

class Strategy
{
    public:
    virtual void A()=0;
    virtual void B()=0;
}

Тогда есть общий предок между Template и Template2:

class AbstractTemplate
{
    public:
    virtual void algorithm()=0;
}

И, наконец, реализация Template и Template2 как «окончательных» классов (= нет необходимости в подклассах).

class Template : AbstractTemplate
{
    public:
    Template(Strategy strategy)
    {
        this.strategy = strategy;
    }
    void algorithm()
    {
        strategy.A();
        strategy.B();
    }
    private:
    Strategy strategy;
}

class Template2 : AbstractTemplate
{
    public:
    Template2(Strategy strategy)
    {
        this.strategy = strategy;
    }
    void algorithm()
    {
        strategy.A();
        strategy.B();
        C();
    }
    private:
    Strategy strategy;
    void C()
    {
        //some stuff
        strategy.A();
        //some stuff
        strategy.B();
    }
}

Перекрытие между Template и Template2 минимально (учитывая, что вам не понадобятся подклассы, я думаю, это нормально).

person Spotted    schedule 01.10.2018
comment
Я думаю, вы только что изменили его шаблон шаблона на шаблон стратегии! Не сказать, что это плохо, но ОП может изучать Шаблон. Одна из тех ситуаций XY? :-) - person bcperth; 02.10.2018
comment
@bcperth Во-первых, да, из-за отсутствия контекста из OP это может быть ситуация XY. Тем не менее, я думаю, что мое решение имеет больше преимуществ, чем просто использование шаблона шаблона: оно позволяет избежать распространения классов. Только с шаблоном вам, возможно, понадобится N ^ 2 класса (N * Template + N * Template2). Со стратегией сложность снижается до N + 2 (N * стратегия + 1 * шаблон + 1 * шаблон2). Но, как вы сказали, если целью OP является изучение шаблона шаблона или ситуации XY, все это не имеет значения и не поможет. - person Spotted; 02.10.2018
comment
Извините, я не ясно изложил свой вопрос, это именно тот ответ, который я хочу, спасибо. - person LtChang; 02.10.2018