Должен ли я составлять каждый метод в моем основном классе, чтобы использовать его (шаблон стратегии)?

Я использовал это руководство, чтобы изучить стратегию шаблон. Я получаю вывод, о котором он говорит, но похоже, что нет возможности использовать метод digHole(). Однако, когда я вызываю метод в конструкторе Dog(), он работает.

Я предполагаю, что это происходит потому, что мне нужно реализовать способ сохранить способность копать в классе животных (например, способность летать), я прав? Означает ли это также, что для каждого действия, которое я хочу, чтобы животное совершило, я должен скомпоновать его в классе Animal, создать интерфейс со способностью, а затем создать два класса, которые реализуют эту способность, что означает, что способность либо реализована, либо нет. т?

У меня также есть некоторые проблемы с формулировкой основной мысли, лежащей в основе паттерна Стратегия. В настоящее время я рассматриваю это как «Инкапсулировать все действия и составить их вместе в одном основном классе». Насколько это точно/уместно?

public class Animal {

    public Flies flyingType;

    public String tryToFly() {
        return flyingType.fly();
    }

    public void setFlyingAbility(Flies newFlyType) {
        flyingType = newFlyType;
    }
}


public class Dog extends Animal {

    public Dog() {
        super();
        setSound("Bark");
        flyingType = new CantFly();
    }

    public void digHole() {
        System.out.println("Dug a hole");
    }
}


public interface Flies {

    String fly();

}

class ItFlies implements Flies {

    public String fly() {
        return "Flying high";
    }

}
class CantFly implements Flies {

    public String fly() {
        return "I can't fly";
    }

}

person Jeroen Vannevel    schedule 10.12.2012    source источник


Ответы (3)


У меня также есть некоторые проблемы с формулировкой основной мысли шаблона «Стратегия».

Возможно, лучший способ разобраться в шаблоне стратегии — это сравнить его с Метод шаблона. Нажмите на ссылки для статей в Википедии.

Оба предполагают определенные проектные решения заранее в базовом классе, но когда, наконец, дело доходит до указания различного поведения для различных подклассов, шаблон шаблона опирается на наследование — переопределение абстрактного метода, определенного в базовом/суперклассе.

Шаблон стратегии основан на композиции — поведение (полет, копание) само по себе является объектом, который можно создать независимо, а затем внедрить в интересующий объект.

В таком языке, как Java, как только вы переопределяете метод в базовом классе, а затем создаете экземпляр объекта, это поведение никогда не может быть изменено. Если вы хотите, чтобы ваш объект работал именно так, используйте наследование. Однако, если вы не знаете до времени выполнения, какое поведение вам понадобится, то стоит приложить дополнительные усилия для проектирования с использованием шаблона стратегии.

то есть способность либо реализована, либо нет?

Хотя учебник, на который вы ссылаетесь, довольно умный, он не является отличной моделью для использования шаблона стратегии. Добавление способности летать собаке настолько нелогично, что отвлекает от урока. С шаблоном стратегии нет ограничений на количество возможных реализаций интересующего алгоритма.

Если вы действительно хотите придерживаться модели животных, вы можете попробовать более универсальные концепции, такие как findFood, escapeFromPredator, findMate, raiseYoung — вещи, которые имеют значение для всех животных, но не будут одинаковыми для каждого экземпляра животного. Две разные собаки могут raiseYoung совершенно по-разному или вести себя по-разному с течением времени, поэтому может потребоваться замена стратегии по мере продолжения имитации животных.

Должен ли я составлять каждый метод в моем основном классе

Вы можете, но вам не нужно, если это становится слишком утомительным - чтобы упростить использование ваших классов, вы можете сделать так, чтобы каждый объект создавал соответствующую стратегию в своем собственном конструкторе. Затем у вас есть выбор — создать объект и использовать поведение по умолчанию или заменить поведение по умолчанию другим в зависимости от приложения.

person Guido Simone    schedule 10.12.2012

Просто создайте абстрактный метод в Animal, чтобы класс Animal тоже стал абстрактным, но нас это не волнует, потому что то, что является животным вообще, не имело смысла. И в каждом классе, наследующем Animal, определите реализацию этого метода.

Это не шаблонная стратегия, но я думаю, что это один из хороших способов сделать то, что вы хотите (как я понял)

person Guillaume    schedule 10.12.2012
comment
В видео он прямо сказал, что не нужно реализовывать метод в каждом классе типа животного из-за дублирования кода. Я не пытаюсь решить реальную проблему, я просто пытаюсь понять механику паттерна Стратегия. - person Jeroen Vannevel; 11.12.2012

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

Итак, если у вас есть сотня видов животных, и некоторые из них могут только летать, некоторые могут только копать, а некоторые могут делать и то, и другое, у вас есть как методы fly, так и digHole в суперклассе.

Однако речь не идет о включении всего поведения в надкласс — если только собаки могут копать, а это вообще не имеет смысла для животных, то вам не имеет смысла помещать digHole в Animal — когда вы хотите, чтобы собака копала, вы, вероятно, должны знать, является ли это Dog в любом случае, или если вы хотите перейти от Animal к Dog (например, чтобы получить всех собак из списка Animal), чтобы вы могли использовать digHole можно использовать явное приведение

person Jeff    schedule 10.12.2012
comment
Вот именно, что мне было неясно. Однако, учитывая, что только собаки могут копать яму, что мне нужно изменить, чтобы я мог заставить собаку копать яму из основного класса? На данный момент это невозможно. У меня сложилось впечатление, что Animal sparky = new Dog(); sparky.digHole(); должен работать при выполнении в основном методе. Однако, когда вы это сделаете, появится исключение, говорящее, что digHole() не реализована в Animal. Так что я все равно должен реализовать это там, даже если это только для собак. - person Jeroen Vannevel; 11.12.2012
comment
Нет. Если вы не хотите менять тип переменной sparky, используйте ((Dog)(sparky)).digHole() — это явное приведение, которое сообщает компилятору, что на самом деле sparky является собакой — в противном случае, насколько это известно компилятору. может быть кошкой или птицей или диглеттом - person Jeff; 11.12.2012