另一个特定于问题的设计问题

时间:2011-07-20 16:02:04

标签: design-patterns class-design

说我有一个具有某些可配置技能的忍者。通过可配置,我的意思是程序读入配置文件并在运行时添加它们。即:

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

现在,假设这些技能需要动态地为Ninja类添加功能。如果我们将Ninja配置为具有跳高技能,那么该类需要遵循CanHighJump接口,使用public void highJump()作为方法。

现在我有两种方法可以考虑这个问题。我的第一反应是使用String颜色的Ninja类,然后使用Reflection添加功能。但是,现在我意识到我也可以通过关系数据库来实现。拥有一个带有String颜色的Ninja类,忘记任何与Ninjas相关的对象 - 相反,每当我需要检查技能时,只需调用数据库检索类可以使用的技能。这是我能提出的唯一两个真正动态的解决方案,我无法理解每个解决方案的设计优缺点。我有一种感觉,数据库解决方案将更具可扩展性,但反射方法在编码时对我来说最有意义。无需查询忍者拥有哪些技能,因为我可以轻松检查界面。

我希望有人能够对这个问题的标准设计解决方案给我一些见解。无论是我想出的两个中的一个,还是更有可能是我没想到的东西。

2 个答案:

答案 0 :(得分:3)

您正在寻找的内容似乎接近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)的实例,否则为null。然后,您可以在IHighJumpCapable上调用highJump()方法。

public static void Main(String args[]) {
    Ninja ninja = new Ninja();
    ninja.AddSkill(new NinjaHighJumpSkill(ninja));
    IHighJumpCapable canHighJump = ninja.GetSkill(IHighJumpCapable.class);
    canHighJump.highJump();
}

答案 1 :(得分:1)

这是Ryan建议的一种扩展。如果需要,以下方法将使忍者执行技能而不必询问和检查技能类型。

看看这是否会增加价值 -

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();
        }

}