例如,对于游戏我有一些技能,即数据对象:
public interface Skill{
public String getName();
}
public class Attack implements Skill{
public String getName(){ return "Attack"; }
public int power;
}
public class Speak implements Skill{
public String getName(){ return "Speak"; }
public String speech;
}
要在游戏中应用技能,我需要一些SkillHandler用于每个相应的技能:
public interface SkillHandler{
public void apply(Skill skill);
}
public class AttackHandler{
@Override
public void apply(Skill skill){
Attack attack=(Attack)skill;
Player player=Global.getPlayer();
Enemy enemy=Global.getEnemy();
enemy.hp=enemy.hp-attack.power;
//some other code for follow up handle
}
}
public class SpeakHandler{
@Override
public void apply(Skill skill){
Speak speak=(Speak)skill;
Label label=new Label(speech);
this.displayOnTop(label);
}
}
我为每个技能使用一个SkillHandler,因为我不希望技能依赖于SkillHandler,而PlayerAttackStateHandler会应用每个技能:
public class PlayerAttackStateHandler{
public PlayerAttackHandler(){
Skill[] skills=Global.getSkills();
for(int i=0;i<skills.length;i++){
SkillHandler skillHandler=null;
if(skills[i].getName().equals("Attack")){
skillHandler=new AttackHandler();
}else if(skills[i].getName().equals("Speak")){
skillHandler=new SpeakHandler();
}
skillHandler.apply(skills[i]);
}
}
}
我知道这个设计格式不正确,因为它至少有两个问题:
如果添加了新的技能以及新的SkillHandler,我需要更新长if-else链,这似乎不遵循开放原则
每个SkillHandler
我的问题是,在这种情况下,是否有任何设计模式可以消除if-else和动态转换(如果可能),同时保持技能不依赖于SkillHandler?
答案 0 :(得分:1)
您的实现似乎与访问者模式有很多共同之处,如下所示:
public interface ISkillable //this is your Skill
{
public int GetPower();
public string GetSpeak();
}
public interface IVisitable //player or npc
{
public void Accept(IVisitor visitor)
}
public interface IVisitor //AttackHandler or SpeakHandler
{
public void ApplySkill(ISkillable skillable)
}
public class Player implements ISkillable, IVisitable
{
...
public void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
public class AttackVisitor implements IVisitor
{
public void Visit(ISkillable skillable)
{
//do something with power
}
}
然后举例说明如何使用
player.Accept(new AttackVisitor(/*you can provide additional info like enemy*/));
player.Accept(new SpeakVisitor());
答案 1 :(得分:0)
请参阅攻击和说出某些代理可能拥有的功能。
我会考虑测试功能/功能:
interface Attacking { void attack(); }
interface Speaking { void speak(); }
Animal animal = ...
Optional<Attacking> attacker = animal.lookup(Attacking.class);
attacker.ifPresent(a -> a.attack());
Optional<Speaking> speaker = animal.lookup(Speaking.class);
speaker.ifPresent(sp -> sp.speak());
Animal不需要实现任何接口,但您可以查找(查找或可能)功能。这在未来是可扩展的,动态的:可以在运行时更改。
实施
private Map<Class<?>, ?> map = new HashMap<>();
public <T> Optional<T> lookup(Class<T> type) {
Object instance = map.get(type);
if (instance == null) {
return Optional.empty();
}
return Optional.of(type.cast(instance));
}
<S> void register(Class<S> type, S instance) {
map.put(type, instance);
}
该实现执行安全的动态转换,因为寄存器确保安全填充(键,值)条目。