Another problem-specific design question
Say I have a Ninja with certain configurable skills. By configurable, I mean the program reads in a configuration file and adds them in at runtime. ie:
Ninja:
color: Red
Skills:
- High Jump
- Invisibility
Now, assume these skills need to dynamically add functionality to the Ninja class. As in, if we configure Ninja to have a High Jump skill, then the class needs to follow the CanHighJump Interface, with public void highJump() as a method.
Now there are two ways I can think of going about this. 开发者_StackOverflow中文版 My first reaction would be to have a Ninja class with String color and then use Reflection to add in the functionality. However, now I realize I could do it through a relational database as well. Have a Ninja class with String color, and forget about any objects relating Ninjas with Skills - instead, whenever I need to check for a skill, just make a call to the database retrieving the possible skills that class can use. Those are the only two truly dynamic solutions I can come up with, and I can't comprehend the design pros/cons of each. I have a feeling the database solution would be far more scale-able, but the reflection method would make most sense to me when coding. No need to query which skills a Ninja has, because I could easily check for the interface.
I'm hoping someone can give me a bit of insight over a standard design solution for this problem. Whether it be one of the two I came up with, or more likely something i didn't think of.
It seems like what you're looking for is close to the 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();
}
}
You can use this pattern to add new capabilities to an object without having to actually implement them in the object. The client will get an instance of IHighJumpCapable
when they call myNinja.getSkill(IHighJumpCapable.class)
if the ninja has this skill, or null otherwise. You can then call the highJump() method on the IHighJumpCapable.
public static void Main(String args[]) {
Ninja ninja = new Ninja();
ninja.AddSkill(new NinjaHighJumpSkill(ninja));
IHighJumpCapable canHighJump = ninja.GetSkill(IHighJumpCapable.class);
canHighJump.highJump();
}
This is a sort of extension to what Ryan has suggested. The following way will make a ninja perform the skill without necessarily asking and checking the skill type if this is desired.
See if this adds value -
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();
}
}
精彩评论