Форум программистов, компьютерный форум CyberForum.ru

Предложить рефакторинг с учетом, что количество языков будет расширяться - C++

Восстановить пароль Регистрация
 
thechicho
0 / 0 / 0
Регистрация: 15.03.2015
Сообщений: 14
Завершенные тесты: 1
17.08.2016, 10:31     Предложить рефакторинг с учетом, что количество языков будет расширяться #1
Предложите ваши варианты решения заданий
2. Есть класс CodeGenerator, который умеет генерить код на разных языках.
Предложите рефакторинг с учетом, что количество языков будет расширяться

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class CodeGenerator
{
public:
    enum Lang {JAVA, C_PLUS_PLUS, PHP};
    CodeGenerator(Lang language) { _language=language; }
    std::string generateCode()
    {
        switch(_language) {
        case JAVA:        //return generated java code
        case C_PLUS_PLUS: //return generated C++ code
        case PHP:         //return generated PHP code
        }
        throw new std::logic_error("Bad language");
    }
    std::string someCodeRelatedThing() // used in generateCode()
    {
        switch(_language) {
        case JAVA:        //return generated java-related stuff
        case C_PLUS_PLUS: //return generated C++-related stuff
        case PHP:         //return generated PHP-related stuff
        }
        throw new std::logic_error("Bad language");
    }
 
private:
    Lang _language;
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
17.08.2016, 10:31     Предложить рефакторинг с учетом, что количество языков будет расширяться
Посмотрите здесь:

что будет? C++
Что будет? C++
C++ Необходимо провести рефакторинг
C++ Оптимизация, рефакторинг кода
C++ Рефакторинг кода задачки
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
John Prick
754 / 687 / 123
Регистрация: 27.07.2012
Сообщений: 1,974
Завершенные тесты: 3
17.08.2016, 11:17     Предложить рефакторинг с учетом, что количество языков будет расширяться #2
Ну тут основная идея - избавиться от switch. Можно предложить шаблоны, хотя м.б. это и не самый хороший способ.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
struct Lang {
    enum E {JAVA, C_PLUS_PLUS, PHP};
};
 
template <Lang::E Language>
class CodeGenerator
{
public:
    std::string generateCode()
    {
        throw /*new*/ std::logic_error("Bad language"); // исключения м.б. лучше по значению кидать
    }
    std::string someCodeRelatedThing() // used in generateCode()
    {
        throw /*new*/ std::logic_error("Bad language");
    }
};
 
template <>
class CodeGenerator<Lang::JAVA>
{
public:
    std::string generateCode() { /*return generated java code*/ }
    std::string someCodeRelatedThing() // used in generateCode()
    { /*return generated java-related stuff*/ }
};
 
template <>
class CodeGenerator<Lang::C_PLUS_PLUS>
{
public:
    std::string generateCode() { /*return generated C++ code*/ }
    std::string someCodeRelatedThing() // used in generateCode()
    { /*return generated C++-related stuff*/ }
};
 
// и так далее специализации для каждого нового языка.
Добавлено через 5 минут
Другой вариант - вместо перечисления создать полноценные классы JAVA, PHP и т.д. функционала для генерации кода и использовать их как стратегии для генератора. Тогда и специализаций не понадобится. Уйдёт лишнее дублирование кода.
notAll
176 / 65 / 16
Регистрация: 27.05.2016
Сообщений: 183
Завершенные тесты: 2
17.08.2016, 12:06     Предложить рефакторинг с учетом, что количество языков будет расширяться #3
Стратегия:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class Language
{
public:
    virtual ~Language() = default;
    virtual std::string code() const = 0;
};
 
class JAVA : public Language
{
public:
    std::string code() const override
    {
        return "generated java code";
    }
};
 
class C_PLUS_PLUS : public Language
{
public:
    std::string code() const override
    {
        return "generated C++ code";
    }
};
 
class PHP : public Language
{
public:
    std::string code() const override
    {
        return "generated PHP code";
    }
};
 
class CodeGenerator
{
public:
    CodeGenerator(Language* language) { _language=language; }
    std::string generateCode()
    {
        if (_language)
            return _language->code();
        else
            throw new std::logic_error("Bad language");
    }
    std::string someCodeRelatedThing()
    {
        return generateCode();
    }
 
    ~CodeGenerator() {delete _language;}
 
private:
    Language* _language;
};
 
int main()
{
    CodeGenerator cgJava(new JAVA);
    CodeGenerator cgPHP(new PHP);
    std::cout << cgJava.generateCode() << "\n";
    std::cout << cgPHP.generateCode() << "\n";
}
John Prick
754 / 687 / 123
Регистрация: 27.07.2012
Сообщений: 1,974
Завершенные тесты: 3
17.08.2016, 13:22     Предложить рефакторинг с учетом, что количество языков будет расширяться #4
Цитата Сообщение от notAll Посмотреть сообщение
Стратегия
Имхо стратегии лучше всё-таки реализовывать через статическое связывание (через шаблоны). Это позволит не возиться с динамической памятью и избавит от некоторых непреднамеренных ошибок типа:
C++
1
2
3
4
Language lang;
{
   CodeGenerator codegen(&lang);
} // <-- Ой! CodeGenerator::~CodeGenerator() {delete _language;}
Да и экономия на виртуальном вызове.

Добавлено через 39 секунд
override - я что-то пропустил? Так можно уже в С++?
DrOffset
6460 / 3834 / 885
Регистрация: 30.01.2014
Сообщений: 6,629
17.08.2016, 13:33     Предложить рефакторинг с учетом, что количество языков будет расширяться #5
Цитата Сообщение от John Prick Посмотреть сообщение
Так можно уже в С++?
Да.
notAll
176 / 65 / 16
Регистрация: 27.05.2016
Сообщений: 183
Завершенные тесты: 2
17.08.2016, 13:41     Предложить рефакторинг с учетом, что количество языков будет расширяться #6
Цитата Сообщение от John Prick Посмотреть сообщение
Это позволит не возиться с динамической памятью
Можно переписать с использованием умных указателей и никаких проблем:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class Language
{
public:
    virtual ~Language() = default;
    virtual std::string code() const = 0;
};
 
class JAVA : public Language
{
public:
    std::string code() const override {return "generated java code";}
};
 
class C_PLUS_PLUS : public Language
{
public:
    std::string code() const override {return "generated C++ code";}
};
 
class PHP : public Language
{
public:
    std::string code() const override {return "generated PHP code";}
};
 
class CodeGenerator
{
public:
    CodeGenerator(std::unique_ptr<Language> language) :
        _language(std::move(language))
    {}
 
    std::string generateCode() const
    {
        if (_language)
            return _language->code();
        else
            throw new std::logic_error("Bad language");
    }
 
    std::string someCodeRelatedThing() const
    {
        return generateCode() + " stuff";
    }
 
private:
    std::unique_ptr<Language> _language;
};
 
int main()
{
    CodeGenerator cgJava(std::make_unique<JAVA>());
    CodeGenerator cgPHP(std::make_unique<PHP>());
 
    std::cout << cgJava.generateCode() << "\n";
    std::cout << cgPHP.someCodeRelatedThing() << "\n";
}
John Prick
754 / 687 / 123
Регистрация: 27.07.2012
Сообщений: 1,974
Завершенные тесты: 3
17.08.2016, 13:53     Предложить рефакторинг с учетом, что количество языков будет расширяться #7
Цитата Сообщение от notAll Посмотреть сообщение
Можно переписать с использованием умных указателей и никаких проблем
Ну основной мой посыл был не совсем в этом. Я просто немного не закончил мысль. Динамические стратегии (так их назовём) можно применить, например, если генератору кода надо будет по ходу выполнения сменить стратегию. Если такой опции не требуется, то имхо лучше использоать статические стратегии.

Всё-таки есть некая разница в удобстве применения:
C++
1
2
3
CodeGenerator cgJava(std::make_unique<JAVA>());
// Или
CodeGenerator<JAVA> cgJava;
Но не навязываю свой мнение.
notAll
176 / 65 / 16
Регистрация: 27.05.2016
Сообщений: 183
Завершенные тесты: 2
17.08.2016, 14:10     Предложить рефакторинг с учетом, что количество языков будет расширяться #8
Пока я вижу только проблемы при использовании статической стратегии. Если, допустим со временем, нам понадобиться поменять интерфейс CodeGenerator - надо будет вносить изменения в каждую специализацию, а их может быть много. А если захотим создать массив CodeGenerator, как быть, - типы CodeGenerator<> то у нас разные будут.
John Prick
754 / 687 / 123
Регистрация: 27.07.2012
Сообщений: 1,974
Завершенные тесты: 3
17.08.2016, 14:21     Предложить рефакторинг с учетом, что количество языков будет расширяться #9
Цитата Сообщение от notAll Посмотреть сообщение
Если, допустим со временем, нам понадобиться поменять интерфейс CodeGenerator - надо будет вносить изменения в каждую специализацию, а их может быть много.
Нет. Тут не будет никаких специализаций:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class JAVA
{
public:
    std::string code() {return "generated java code";}
};
 
template <class LangPolicy>
class CodeGenerator : public LangPolicy
{
public:
    std::string generateCode() const
    {
        return code();
    }
};
Цитата Сообщение от notAll Посмотреть сообщение
А если захотим создать массив CodeGenerator, как быть, - типы CodeGenerator<> то у нас разные будут.
Это если захотим создать. Перед тем как рефакторить класс, надо как раз подумать над тем, как этот класс будет применяться. Но и тут ничего не мешает создать базовый абстрактный класс CodeGeneratorAbstract, а функцию generateCode сделать виртуальной. Шаблонный класс будет наследовать от него.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
17.08.2016, 18:20     Предложить рефакторинг с учетом, что количество языков будет расширяться
Еще ссылки по теме:

рефакторинг -> переименование C++
Рефакторинг кода C++
Калькулятор: Рефакторинг, принцип единой ответственности C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
hoggy
5230 / 2121 / 404
Регистрация: 15.11.2014
Сообщений: 4,812
Завершенные тесты: 1
17.08.2016, 18:20     Предложить рефакторинг с учетом, что количество языков будет расширяться #10
Цитата Сообщение от notAll Посмотреть сообщение
Если, допустим со временем, нам понадобиться поменять интерфейс CodeGenerator - надо будет вносить изменения в каждую специализацию, а их может быть много.
в случая с дин. полиморфизмом - каждого наследника.

те же яйца только сбоку.

Цитата Сообщение от notAll Посмотреть сообщение
А если захотим создать массив CodeGenerator, как быть
не нужно решать проблемы будущего, которое может и не наступить.


ps:
я за абстрактный интерфейс CodeGenerator и шаблоно-наследников.
Yandex
Объявления
17.08.2016, 18:20     Предложить рефакторинг с учетом, что количество языков будет расширяться
Ответ Создать тему
Опции темы

Текущее время: 03:39. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru