Нарушение провайдера

Я задал вопрос об использовании стратегии pattern и LSP, но ответы были неоднозначными, и в долгосрочной перспективе это не очень хорошая идея. Однако в комментарии внизу моего вопроса говорилось, что, хотя я не нарушаю LSP, я нарушаю Принцип разделения интерфейса, который гласит:

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

Предположим, у меня был такой класс оружия:

public final Weapon{

    private final String name;
    private final int damage;
    private final List<AttackStrategy> validactions;
    private final List<Actions> standardActions;

    public Weapon(String name, int damage, List<AttackStrategy> standardActions, List<Actions> attacks)
    {
        this.name = name;
        this.damage = damage;
        standardActions = new ArrayList<Actions>(standardActions);
        validAttacks = new ArrayList<AttackStrategy>(validActions);
    }

    public void standardAction(String action){} // -- Can call reload or aim here.  

    public int attack(String action){} // - Call any actions that are attacks. 

}

Интерфейс и реализация:

public interface AttackStrategy{
    void attack(Enemy enemy);
}

public class Shoot implements AttackStrategy {
    public void attack(Enemy enemy){
        //code to shoot
    }
}

public class Strike implements AttackStrategy {
    public void attack(Enemy enemy){
        //code to strike
    }
}

Использование:

List<AttackStrategy> actions = new ArrayList<AttackStrategy();
actions.add(new Shoot())

List<Actions> standardActionactions = new ArrayList<Actions>();
actions.add(new Reload(10))

Weapon rifle = new Weapon("Sniper Rifle", 5, standardActionactions, actions);

List<AttackStrategy> actions = new ArrayList<AttackStrategy();
actions.add(new Swing())

List<Actions> standardActionactions = new ArrayList<Actions>();
actions.add(new Drop())

Weapon sword = new Weapon("Standard Sword", 10, standardActionactions, actions);

У меня есть два Оружия, и оба ведут себя по-разному, при этом оба могут использоваться для атаки, у обоих разные действия, специфичные для каждого типа. Например, Sword не должен и по логике моей коллекции не может вызывать или реализовывать перезагрузку в любом случае.

В моей текстовой приключенческой игре, если вы передадите "reload" в sword.standardAction("reload"), внутренняя логика проверит, содержит ли список объект перезарядки, и если да, то сделайте это, если нет, оружие не не способен и, следовательно, не может, поэтому игнорирует его.

Я нарушаю правила провайдера?

Мой меч никогда не будет реализовывать reload, если клиент не решит реализовать его, я не заставляю клиента признать, что Sword знает о методе Reload, который они никогда не будут использовать.


person Community    schedule 23.10.2017    source источник
comment
На самом деле вы не нарушаете ISP, но вы также не используете преимущества системы типов. Как насчет того, чтобы отказаться от некоторой гибкости, чтобы определить общие абстракции? Например. все оружие может иметь reload, lightAttack, normalAttack, specialAttack и соответствующую стратегию для каждого.   -  person plalx    schedule 24.10.2017
comment
@plalx - Моя главная проблема в том, почему меч должен знать о перезагрузке? и если Sword игнорирует перезагрузку и оставляет поле пустым, не нарушает ли это LSP? В любом случае кажется, что я нарушаю какой-то принцип, просто игнорируя его, чтобы получить игру с несколькими видами оружия.   -  person    schedule 24.10.2017
comment
@plalx - Учитывая, что я следовал правилам сайта и пытался сам, как бы вы решили это, не нарушая LSP / ISP или любого другого принципала SOLID?   -  person    schedule 24.10.2017


Ответы (1)


Похоже, что абстракция оружия слишком общая. Я бы разбил это на более мелкие абстракции

  1. Оружие (абстрактное или интерфейсное — выбирайте сами)

    • attack
  2. GunBasedWeapon (расширяет оружие) (пистолеты, винтовки, лазерные пушки, мегатрон 80-х)

    • aim
    • перезагрузить
    • атака (выдает OutOfBulletException)
  3. HandheldWeapon (расширяет оружие) (мечи, дубинки, цепи и т. д.)

    • attack (throws CallousesOnHandHurtException after 100 hits without lotion)
    • применитьлосьон
  4. ThrowableWeapon (расширяет оружие) (бумеранги)

    • attack (throws SomebodyElseCaughtMyBoomerangException, and then ImHosedException after that)
  5. WeaponAction — каждый класс оружия теперь может иметь список допустимых действий, если кто-то каким-то образом передаст «applyLotion» в GunBasedWeapon, только класс Gun будет знать, что это недействительно.

person Goose    schedule 24.10.2017
comment
Спасибо за это, но я хотел избежать кастинга, который, если бы я использовал этот шаблон, мне пришлось бы получить доступ к методам, специфичным для класса. Разве кастинг не то, чего вы хотели бы избежать? - person ; 24.10.2017