Паттерн Стратегия

C++*
Есть небольшой вопрос по данному шаблону. Прочитал статью habrahabr.ru/blogs/programming/132929/ Вроде даже понял, что к чему. Пытаюсь реализовать, но не получается. Дело в том, что в примерах просто вызывается метод из другого класса, который выводит текстовую строку. В моем случае, требуется, чтобы вызванный метод изменял параметры объекта главного класса. То есть вот так:

class changeValue
{
public:
    changeValue();
    ~changeValue();
    virtual void Change() = 0;
};

changeValue::changeValue() {}
changeValue::~changeValue() {}

class General
{
public:
    General();
    ~General();
    float a;
    void changeit();
    changeValue *object;
};

General::General() {a=0;}
General::~General() {}
void General::changeit()
{
    object->Change();
}

class changeValueTo1 : public changeValue
{
    changeValueTo1();
    ~changeValueTo1();
    void Change();
};

changeValueTo1::changeValueTo1() {}
changeValueTo1::~changeValueTo1() {}
void changeValueTo1::Change()
{
    //должен изменить значение параметра a объекта класса MyClass на 1
}

class MyClass : public General
{
    MyClass();
    ~MyClass();
};

MyClass::MyClass() {
   object = new changeValueTo1;
}

MyClass::~MyClass() {
   delete object;
}

Как реализовать метод void changeValueTo1::Change() так, чтобы он имел доступ к параметрам класса MyClass?
23 февраля в 02:33
1
PaGrom 2,6

отсортировано по дате по оценке
ответы (3)

+2
rtorsten #
Как реализовать метод void changeValueTo1::Change() так, чтобы он имел доступ к параметрам класса MyClass?

Наиболее простой способ, как уже и сказали сделать перекрестную ссылку/указатель.
class changeValueTo1 : public changeValue
{
public:
    changeValueTo1(General * p) : _parent(p) {}
    ~changeValueTo1() {}
    void Change();

private:
    General * _parent;
};

void changeValueTo1::Change()
{
    //должен изменить значение параметра a объекта класса MyClass на 1
    _parent->a = 5;
}

MyClass::MyClass() {
   object = new changeValueTo1(this);
}


В данном случае это параметр класса General, а не MyClass как ты указал в комментарии. Если нужно именно MyClass то необходимо в changeValueTo1 изменить тип указателя.
Спасибо вам большое, помогло. PaGrom, 23 февраля в 13:14
+2
taliban #
Перекрестная ссылка Вам нужна, хотя это не лучший вариант, часто причина утечек, а обязательна ли стратегия? Вообще лично я стараюсь придерживаться правила: «проще писать проще, потом и поддерживать будет проще и дописывать будет проще».
class changeValue
{
public:
    changeValue( objToChangeValue );
    ~changeValue();
    virtual void Change() = 0;
};
taliban, 23 февраля в 03:20
+ Вам нужен интерфейс для принимаемого обьекта taliban, 23 февраля в 03:21
Зачем усложнять себе жизнь? Просто чтоб использовать паттерн? Оно точно того стоит? taliban, 23 февраля в 03:21
Не совсем понял как это реализовать. Можете подробнее объяснить на моем примере? К сожалению, именно стратегию использовать надо. Не моя прихоть, а преподавателя. PaGrom, 23 февраля в 03:30
Я в с++ не силен, снизу вроде как правильно человек написал, именно то что я имел ввиду. taliban, 23 февраля в 12:03
0
retran #
Если у вас возникла необходимость из стратегии как-то модифицировать контекст — то скорее всего вы неправильно произвели декомпозицию классов и скорее всего нарушили Single Responsibility Principle.

Грубо говоря, у вас должен быть отдельный класс-контекст и отдельный класс из домена, объекты которого и обрабатывает стратегия. И тогда его легко можно прокинуть в стратегию, например, через аргументы методов.

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

class Context
attr_accessor :strategy

def initialize(strategy)
@strategy = strategy
end

def set_strategy(strategy)
@strategy = strategy
end

def do(obj)
strategy.do(obj)
end
end

def StrategyA
def do(obj)
obj.modify("A")
end
end

def StrategyB
def do(obj)
obj.modify("B")
end
end

class Obj
attr_reader :name

def modify(name)
@name = name
end

def say
puts @name
end
end

context = Context.new(StrategyA.new)
obj = Obj.new
context.do(obj)
retran, 27 февраля в 18:13

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.