Еще один проблемный вопрос дизайна - PullRequest
2 голосов
/ 20 июля 2011

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

Ninja:
  color: Red
  Skills:
    - High Jump
    - Invisibility

Теперь предположим, что эти навыки необходимы для динамического добавления функциональности в класс ниндзя.Например, если мы сконфигурируем Ninja для получения навыка High Jump, то класс должен следовать интерфейсу CanHighJump с открытым void highJump () в качестве метода.

Теперь есть два способа, которыми я могу подумать о переходеоб этом.Моя первая реакция будет иметь класс Ninja с цветом String, а затем использовать Reflection, чтобы добавить функциональность.Однако теперь я понимаю, что могу сделать это и через реляционную базу данных.Возьмите класс ниндзя с цветом String и забудьте о любых объектах, связанных с ниндзя с навыками - вместо этого, когда мне нужно проверить навык, просто позвоните в базу данных, чтобы найти возможные навыки, которые может использовать класс.Это только два действительно динамичных решения, которые я могу придумать, и я не могу понять плюсы и минусы каждого из них.У меня есть ощущение, что решение для базы данных будет гораздо более масштабируемым, но метод отражения будет наиболее целесообразным для меня при кодировании.Не нужно спрашивать, какими навыками обладает ниндзя, потому что я легко могу проверить интерфейс.

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

Ответы [ 2 ]

3 голосов
/ 21 июля 2011

Кажется, что то, что вы ищете, близко к Capability Pattern .

public interface IHasSkills {
    public <T> getSkill(Class<T> skill);
}

public interface ICanAddSkills extends IHasSkills {
    public void addSkill(ISkill skill)
}

public class Ninja implements ICanAddSkills {
    private List<ISkill> _skills;

    public void addSkill(ISkill skill) {
        _skills.Add(skill);
    }

    public <T> GetSkill(Class<T> skillType) {
        for(ISkill skill : _skills) {
           if(skill instanceof skillType) return skill;
        }
        return null;
    }
}

public interface ISkill{}

public interface IHighjumpSkill extends IHighJumpCapable{
    public void highJump();
}

public class NinjaHighJumpSkill implements IHighJumpCapable{
    private Ninja _canHighJump;
    public NinjaHighJumpSkill(Ninja ninja) {
        _canHighJump = ninja;
    }

    @Override
    public void highJump() {
        //Note that this could be combined with the [Property Pattern][2] 
        //(which was referenced in another answer) to set/get arbitrary
        //properties on the ninja.
        _canHighJump.DoWhateverAHighJumpDoes();
    }
}

Этот шаблон можно использовать для добавления новых возможностей к объекту без необходимости фактически реализовывать их в объекте.Клиент получит экземпляр IHighJumpCapable при вызове myNinja.getSkill(IHighJumpCapable.class), если у ниндзя есть этот навык, или ноль в противном случае.Затем вы можете вызвать метод highJump () для IHighJumpCapable.

public static void Main(String args[]) {
    Ninja ninja = new Ninja();
    ninja.AddSkill(new NinjaHighJumpSkill(ninja));
    IHighJumpCapable canHighJump = ninja.GetSkill(IHighJumpCapable.class);
    canHighJump.highJump();
}
1 голос
/ 21 июля 2011

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

Проверьте, добавляет ли это значение -

public class Ninja implements ICanAddSkills {
private List<ISkill> _skills;

public void addSkill(ISkill skill) {
    _skills.Add(skill);
}

public <T> getSkill(Class<T> skillType) {
    for(ISkill skill : _skills) {
       if(skill instanceof skillType) return skill;
    }
    return null;
    }
}

    public interface ISkill{
        public void performSkill();
    }

public interface IHighjumpSkill extends ISkill,IHighJumpCapable{
    public void highJump();
}

public class NinjaHighJumpSkill implements IHighjumpSkill{
    private Ninja _canHighJump;
    public NinjaHighJumpSkill(Ninja ninja) {
        _canHighJump = ninja;
    }

    @Override
    public void highJump() {
        _canHighJump.DoWhateverAHighJumpDoes();
    }

    // delgate to whatever this skill can do
    @Override
    public void performSkill() {
        highJump();
    }
}


public static void Main(String args[]) {
    Ninja ninja = new Ninja();
    ninja.AddSkill(new NinjaHighJumpSkill(ninja));
    // loop through skills and perform actions using performSkill()

     for(ISkill skill : _skills) {
          skill.performSkill();
        }

}
...