Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.67/9: Рейтинг темы: голосов - 9, средняя оценка - 4.67
GERALD2799
10 / 10 / 13
Регистрация: 27.09.2016
Сообщений: 242
Завершенные тесты: 2
1

Есть ли какой паттерн для решения подобной задачи?

08.09.2018, 21:54. Просмотров 1660. Ответов 18
Метки нет (Все метки)

у меня есть абстрактный класс, для фигур. он имеет метод для записи в файл, который переопределяет все потомки. а как реализовать метод для считывания? сделал метод в абстрактном классе, но добавлено новых фигур в иерархии трудно. приходится постоянно менять этот метод. а если я построю библиотеку, пользователь который наследует класс фигур не сможет считывать свой класс из файла. есть какой паттерн или просто способ решения такой задачи?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
VolShape* VolShape::MakeInstance(std::ifstream& fin)
{
    int y; double h, r, a, b;
    string name;
    fin >> name;
    if (name == "Cylinder")
    {
        fin >> h >> r;
        return new Cylinder(h,r);
    }
    if (name == "Paralelepiped")
    {
        fin >> h >> a >> b; return new Paralelepiped(h,a,b);
    }
    throw BadClassname(name.c_str());
}
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
08.09.2018, 21:54
Ответы с готовыми решениями:

Можно ли переменную финализировать для подобной задачи?
Так ошибки не возникает const N=222; char Buf; Но если так, то ошибка int a=222; ...

Где используется тот ли иной язык программирования? Какой из них выбрать для решения задачи?
спросил в этой теме из-за того что не нашел где можно почитать где используется тот ли иной язык...

Какой язык программирование выбрать для решения следующей задачи
Здравствуйте, уважаемые форумчане-программисты! Я являюсь полнейшей зеленью и обладаю нулевым...

Воспользуйтесь модулем Triangle для решения какой-нибудь геометрической задачи
Пожалуйста помогите напишите код я не могу понять как это сделать :gsorry::flirt::-* ...

Какой метод (или подход к решению) выбрать для решения следующей задачи оптимизации?
Постановка задачи: Есть функция - вектор значений управляющих параметров на входе, вектор значений...

18
notAll
475 / 191 / 67
Регистрация: 27.05.2016
Сообщений: 498
Завершенные тесты: 2
08.09.2018, 23:41 2
Цитата Сообщение от GERALD2799 Посмотреть сообщение
а как реализовать метод для считывания?
Аналогично, как и:
Цитата Сообщение от GERALD2799 Посмотреть сообщение
он имеет метод для записи в файл, который переопределяет все потомки
1
GERALD2799
10 / 10 / 13
Регистрация: 27.09.2016
Сообщений: 242
Завершенные тесты: 2
09.09.2018, 09:10  [ТС] 3
notAll, аналогично не получится. я хочу иметь коллекцию фигур. тогда мне надо через полиморфными указатель на родительскую фигуру определить, какой тип в файле.обычным полиморфизмом такое не получается сделать.
0
Croessmah
++Ͻ
15816 / 8951 / 1719
Регистрация: 27.09.2012
Сообщений: 21,992
Записей в блоге: 2
Завершенные тесты: 2
09.09.2018, 09:39 4
GERALD2799, как вариант, родительский класс содержит мапу с десериализаторами и функцию регистрации десериализатора. Каждый наследник регистрирует функцию-десериализатор. Ну а MakeInstance вызывает нужный десериализатор в зависимости от name.
2
09.09.2018, 09:39
GERALD2799
10 / 10 / 13
Регистрация: 27.09.2016
Сообщений: 242
Завершенные тесты: 2
09.09.2018, 09:45  [ТС] 5
Croessmah, звучит замечательно и я так понимаю map статический, но как мне это написать, если наследует кто-то из родительского класса и он не знаю о такой логике?даже если ввести еще один абстрактный метод для добавления в map, как пользователь должен знать, что в нем писать
0
ValeryS
Модератор
7883 / 5865 / 768
Регистрация: 14.02.2011
Сообщений: 20,158
Завершенные тесты: 1
09.09.2018, 09:51 6
Цитата Сообщение от GERALD2799 Посмотреть сообщение
тогда мне надо через полиморфными указатель на родительскую фигуру определить, какой тип в файле.
сделай первый байт идентификатором фигуры
а в родительском классе статический метод чтения
метод считывает первый байт, определяет какая фигура, создает эту фигуру, наверное динамически, и вызывает уже метод чтения из данной фигуры
примерно так

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static Figure* Figure::Load(file)
{
 Figure *obFigure=nullptr;
 uint8_t fig= read(file,1);
switch( fig)
{
 case 0:
  obFigure=new Line;
 break;
 case 1:
   obFigure=new Circle;
 case 2:
   obFigure=new Rectangle;
................
 
}
obFigure->Load(file);
return obFigure;
 
}
1
GERALD2799
10 / 10 / 13
Регистрация: 27.09.2016
Сообщений: 242
Завершенные тесты: 2
09.09.2018, 09:55  [ТС] 7
ValeryS, вы меня не поняли. я именно так и сделал. проблема возникает при наследовании. это библиотека. пользователь может наследовать от абстрактного класса. но если он это сделает метод Figure :: Load не будет работать для его класса, а только для тех классов, которые там прописаны
0
ValeryS
Модератор
7883 / 5865 / 768
Регистрация: 14.02.2011
Сообщений: 20,158
Завершенные тесты: 1
09.09.2018, 10:00 8
можно попробовать добавить еще один абстрактный класс
и пускай пользователь работает с этим классом сам все реализует
а в свитч добавить ветку
C++
1
2
default:
   obFigure=new OtsherFigure;
1
GERALD2799
10 / 10 / 13
Регистрация: 27.09.2016
Сообщений: 242
Завершенные тесты: 2
09.09.2018, 10:04  [ТС] 9
ValeryS, мне кажется это так себе вариант. усложняет архитектуру и работу с классами для пользователя
0
Ygg
1868 / 475 / 189
Регистрация: 10.02.2018
Сообщений: 1,036
09.09.2018, 10:22 10
Есть паттерн "фабрика классов".
1
GERALD2799
10 / 10 / 13
Регистрация: 27.09.2016
Сообщений: 242
Завершенные тесты: 2
09.09.2018, 10:29  [ТС] 11
Ygg, с того, что я нашел в интернете там используется та же if-else_if-else_if hard-coded-система что и у меня. возможно, я что-то не то нашел, можете привести пример, именно для решения моей задачи
0
ValeryS
Модератор
7883 / 5865 / 768
Регистрация: 14.02.2011
Сообщений: 20,158
Завершенные тесты: 1
09.09.2018, 10:47 12
Цитата Сообщение от GERALD2799 Посмотреть сообщение
усложняет архитектуру и работу с классами для пользователя
пользователю дается на откуп абстрактный класс OtsherFigure, пускай делает с ним что хочет и наследует все что захочет
1
GERALD2799
10 / 10 / 13
Регистрация: 27.09.2016
Сообщений: 242
Завершенные тесты: 2
09.09.2018, 10:52  [ТС] 13
ValeryS, но откуда пользователь должен знать, что его класс OtherFigure, а не FigureBase? кроме того, почему одни фигуры наследуют из одного класса, а для пользователя создается особый класс? нужно также помнить, какие фигуры у тебя особые, а какие стандартные. ну не знаю, может я и ошибаюсь, но мне такой вариант не нравится
0
ValeryS
Модератор
7883 / 5865 / 768
Регистрация: 14.02.2011
Сообщений: 20,158
Завершенные тесты: 1
09.09.2018, 11:05 14
Цитата Сообщение от GERALD2799 Посмотреть сообщение
но откуда пользователь должен знать, что его класс OtherFigure, а не FigureBase?
из документации к библиотеке
Цитата Сообщение от GERALD2799 Посмотреть сообщение
но мне такой вариант не нравится
наше дело предложить, ваше оказаться

Добавлено через 3 минуты
Цитата Сообщение от GERALD2799 Посмотреть сообщение
почему одни фигуры наследуют из одного класса, а для пользователя создается особый класс?
есть int, на его основе создали класс Point состоящий из двух int( ну и еще кое чего) не возникает вопрос почему мы должны координаты наследовать от Point а не от int
1
GERALD2799
10 / 10 / 13
Регистрация: 27.09.2016
Сообщений: 242
Завершенные тесты: 2
09.09.2018, 11:07  [ТС] 15
ValeryS, возможно потому, что Point не наследует int, а содержит. ну но это уже вопрос архитектуры, которые не касаются моей проблемы
0
woldemas
534 / 357 / 189
Регистрация: 06.09.2013
Сообщений: 1,058
Завершенные тесты: 1
09.09.2018, 11:29 16
GERALD2799, сталкивался с похожей проблемой, ничего тогда не придумал, лучше способа предложенного Croessmah, так что думаю вам лучше на него обратить внимание. Правда, я тогда это писал на языке поддерживающем статические конструкторы и там регистрацию удобно было в них прописывать. В C++ насколько я знаю статических конструкторов нет, поэтому придется как-то выкручиваться.
Вот я прикинул, как это на C++ может выглядеть:
Кликните здесь для просмотра всего текста

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
#include<iostream>
#include<string>
#include <map>
#include <functional>
#include <sstream>
 
struct Model {
    virtual void read(std::istream &is) {};           
    virtual void write(std::ostream &os) {};      
    virtual void name() const = 0;
    static std::map<std::string, std::function<Model*()> > factory;    
    static Model *create_instance(std::istream &is) {
        std::string name; is >> name;
        Model *instance = factory[name]();
        instance->read(is);
        return instance;
    }
    static void register_model(const std::string &str, std::function<Model*()> func) {
        factory[str] = func;
    }
};
std::map<std::string, std::function<Model*()>> Model::factory;
 
struct Cube : public Model {    
    void name() const override;
};
 
void Cube::name() const {
    std::cout << "Cube";
}
 
int main() {      
    Model::register_model("Cube", [](){ return new Cube();});
    std::istringstream iss("Cube");
    Model *m = Model::create_instance(iss);
    m->name();
    delete m;
    return 0;
}
1
Ygg
1868 / 475 / 189
Регистрация: 10.02.2018
Сообщений: 1,036
09.09.2018, 11:29 17
Лучший ответ Сообщение было отмечено GERALD2799 как решение

Решение

Цитата Сообщение от GERALD2799 Посмотреть сообщение
можете привести пример, именно для решения моей задачи
что-то вроде такого
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <fstream>
#include <string>
#include <map>
 
class CMyBase
{
public:
    CMyBase() {}
    virtual ~CMyBase() {}
 
    static CMyBase* Create() { return 0; }
    static const char* StaticName() { return 0; }
 
    virtual const char* Name() = 0;
    virtual void Save(std::ofstream& s) = 0;
    virtual void Load(std::ifstream& s) = 0;
};
 
class CMyClassA : public CMyBase
{
public:
    int a1;
 
public:
    CMyClassA() { a1 = 0; }
    virtual ~CMyClassA() {}
 
    static CMyBase* Create() { return new CMyClassA; }
    static const char* StaticName() { return "ClassA"; }
 
    virtual const char* Name() { return StaticName(); }
    virtual void Save(std::ofstream& s) { s << a1 << ' '; }
    virtual void Load(std::ifstream& s) { s >> a1; }
};
 
class CMyClassB : public CMyBase
{
public:
    int b1;
    int b2;
 
public:
    CMyClassB() { b1 = b2 = 0; }
    virtual ~CMyClassB() {}
 
    static CMyBase* Create() { return new CMyClassB; }
    static const char* StaticName() { return "ClassB"; }
 
    virtual const char* Name() { return StaticName(); }
    virtual void Save(std::ofstream& s) { s << b1 << ' ' << b2 << ' '; }
    virtual void Load(std::ifstream& s) { s >> b1 >> b2; }
};
 
class CMyFabric
{
public:
    typedef CMyBase*(*CreateFunc)();
    std::map<std::string, CreateFunc> cmap;
 
public:
    CMyFabric() {}
    virtual ~CMyFabric() {}
 
    void RegisterClass(std::string name, CreateFunc fun)
    {
        cmap.insert(std::pair<std::string, CreateFunc>(name, fun));
    }
 
    CMyBase* Load(std::ifstream& s)
    {
        std::string name;
        s >> name;
        CMyBase* obj = cmap[name]();
        if (obj)
            obj->Load(s);
        return obj;
    }
 
    void Save(std::ofstream& s, CMyBase* obj)
    {
        s << obj->Name() << ' ';
        obj->Save(s);
    }
};
 
 
int main()
{
    CMyFabric fabr;
    fabr.RegisterClass(CMyClassA::StaticName(), CMyClassA::Create);
    fabr.RegisterClass(CMyClassB::StaticName(), CMyClassB::Create);
 
    CMyClassA a;
    a.a1 = 1;
    CMyClassB b;
    b.b1 = 2;
    b.b2 = 3;
 
    {
        std::ofstream s("test.txt");
        fabr.Save(s, &a);
        fabr.Save(s, &b);
    }
 
    {
        std::ifstream s("test.txt");
        CMyBase* pa = fabr.Load(s);
        CMyBase* pb = fabr.Load(s);
        int brk=0;
    }
 
    return 0;
}
1
Croessmah
++Ͻ
15816 / 8951 / 1719
Регистрация: 27.09.2012
Сообщений: 21,992
Записей в блоге: 2
Завершенные тесты: 2
09.09.2018, 11:50 18
Лучший ответ Сообщение было отмечено GERALD2799 как решение

Решение

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//g++  5.4.0
 
#include <iostream>
#include <map>
#include <functional>
 
struct InputFailure{/*...*/};
struct BadClassname{/*...*/};
 
class VolShape
{
public:
    using DeserializerType = std::function<VolShape *(std::string const &, std::istream &)>;
    static bool RegDeserializer(std::string name, DeserializerType func)
    {
        return get_deserializers().emplace(std::move(name), std::move(func)).second;
    }
    
    static VolShape * MakeInstance(std::istream & fin)
    {
        std::string name;
        if (!(fin >> name)) {
            if (fin.eof()) {
                return nullptr;
            }
            throw InputFailure(/*...*/);
        }
        auto const & dsrls = get_deserializers();
        auto it = dsrls.find(name);
        if (it == dsrls.end()) {
            throw BadClassname(/*...*/);
        }
        return it->second(name, fin);
    }
    
    virtual ~VolShape() {}
private:
    static std::map<std::string, DeserializerType> & get_deserializers()
    {
        static std::map<std::string, DeserializerType> deserializers;
        return deserializers;
    }
};
 
 
struct Cylinder: VolShape
{  
    static Cylinder * make_from_istream(std::string const &, std::istream &)
    {
        std::cout << "Cylinder" << std::endl;
        //чтение из потока
        return new Cylinder(/*...*/);
    }
};
 
 
 
struct Paralelepiped: VolShape
{
    static Paralelepiped * make_from_istream(std::string const &, std::istream &)
    {
        std::cout << "Paralelepiped" << std::endl;
        //чтение из потока
        return new Paralelepiped(/*...*/);
    }
};
 
 
 
 
int main()
{
    VolShape::RegDeserializer("Cylinder", Cylinder::make_from_istream);
    VolShape::RegDeserializer("Paralelepiped", Paralelepiped::make_from_istream);
    while (VolShape * object = VolShape::MakeInstance(std::cin)) 
    {        
    }
}
http://rextester.com/AQOD92067
1
notAll
475 / 191 / 67
Регистрация: 27.05.2016
Сообщений: 498
Завершенные тесты: 2
09.09.2018, 11:55 19
Лично я бы делал на абстрактной фабрике, как то так:
Кликните здесь для просмотра всего текста
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
class LoadFactory;
 
class VolShape
{
public:
    virtual ~VolShape() = default;
    VolShape* makeInstance(std::ifstream& fin);
 
protected:
    LoadFactory *_loadFactory {nullptr};
};
 
class Cylinder : public VolShape
{
public:
    Cylinder(double, double);
};
 
class Paralelepiped : public VolShape
{
public:
    Paralelepiped(double, double, double);
};
 
class LoadFactory
{
public:
    virtual ~LoadFactory() = default;
    virtual VolShape* createShape(std::ifstream& fin) const = 0;
};
 
class CylinderFactory : public LoadFactory
{
public:
    VolShape* createShape(std::ifstream& fin) const override
    {
        std::string name;
        fin >> name;
        if (name == "Cylinder")
        {
            double h, r;
            fin >> h >> r;
            return new Cylinder(h,r);
        }
 
        return nullptr;
    }
};
 
class ParalelepipedFactory : public LoadFactory
{
public:
    VolShape* createShape(std::ifstream& fin) const override
    {
        std::string name;
        fin >> name;
        if (name == "Paralelepiped")
        {
            double h, a, b;
            fin >> h >> a >> b;
            return new Paralelepiped(h, a, b);
        }
 
        return nullptr;
    }
};
 
VolShape* VolShape::makeInstance(std::ifstream& fin)
{
    if (VolShape * shape = _loadFactory ? _loadFactory->createShape(fin) : nullptr)
        return shape;
 
    throw std::logic_error("Can't create shape");
}
 
Cylinder::Cylinder(double, double)
{
    _loadFactory = new CylinderFactory();
}
 
Paralelepiped::Paralelepiped(double, double, double)
{
    _loadFactory = new ParalelepipedFactory();
}
1
09.09.2018, 11:55
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
09.09.2018, 11:55

Кригинг - есть ли библиотеки для решения данной задачи за более "быстрое" время
Реализован кригинг, но решается за длительное время, особенно в 3d-пространстве. Есть ли библиотеки...

Какой метод решения оптимизационной задачи выбрать
Подскажите какой метод решения оптимизационной задачи? Есть 14 параметров с Мин и Макс значениями...

Есть ли короткий путь решения задачи?
Даны три действительных числа. Возвести в квадрат те из них, значения которых неотрицательны. ...


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

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.