我有一个像这样的ReloadableWeapon类:
public class ReloadableWeapon {
//keeping the design really simple, took out weapon logic.
private int numberofbullets;
public ReloadableWeapon(int numberofbullets){
this.numberofbullets = numberofbullets;
}
public void attack(){
numberofbullets--;
}
public void reload(int reloadBullets){
this.numberofbullets += reloadBullets;
}
}
使用以下interface
:
public interface Command {
void execute();
}
并像这样使用它:
public class ReloadWeaponCommand implements Command {
private int reloadBullets;
private ReloadableWeapon weapon;
//Is is okay to specify the number of bullets?
public ReloadWeaponCommand(ReloadableWeapon weapon, int bullets){
this.weapon = weapon;
this.reloadBullets = bullets;
}
@Override
public void execute() {
weapon.reload(reloadBullets);
}
}
Cilent:
ReloadableWeapon chargeGun = new ReloadableWeapon(10);
Command reload = new ReloadWeaponCommand(chargeGun,10);
ReloadWeaponController controlReload = new ReloadWeaponController(reload);
controlReload.executeCommand();
我想知道,使用命令pattern
和我见过的示例,除了命令所作用的对象之外,没有其他parameters
。
This example, alters the execute method to allow for a parameter。
Another example, more close to what I have here, with parameters in the constructor。
在命令pattern
中包含参数是不好的做法/代码嗅觉,在这种情况下,constructor
是否有子弹数?
答案 0 :(得分:6)
我认为在执行中添加参数不会是糟糕的设计或违反命令模式。
这完全取决于你想如何使用Command Object: Singleton或Prototype 范围。
如果使用Prototype范围,则可以在Constructor方法中传递命令参数。每个命令实例都有自己的参数。
如果使用Singleton范围(共享实例),则可以在execute方法中传递命令参数。对于这种情况,命令的单例应该是线程安全的。该解决方案也是IoC / DI框架的朋友。
答案 1 :(得分:0)
考虑一个案例,你手头有95颗子弹,你已经制作了9个命令,10个子弹和1个命令,5个子弹。而且你已经将这些命令提交给了Invoker,现在调用者不必担心会留下多少子弹。他只会执行命令。另一方面,如果调用者必须在运行时提供子弹,那么可能是提供的子弹数量不可用。
我的观点是,Invoker不必担心执行命令所需的任何额外信息。正如在wiki中所提到的,“对象用于封装执行操作或稍后触发事件所需的所有信息”
答案 2 :(得分:0)
考虑相关的' 扩展模式'为了坚持自上而下的控制范式' 控制反转'。
此模式(命令模式)通常与复合,迭代器和访问者设计模式一起使用。
命令是' 头等对象'。因此,保护封装的完整性至关重要。此外,将控制从上到下反转到自下而上,违反了面向对象设计的基本原则,尽管我看到人们一直在暗示......
Composite模式允许您在迭代数据结构中存储命令。
在继续前进之前,虽然您的代码仍然可以管理,但请查看这些模式。
这个帖子中有一些合理的观点。 @Loc让它最接近IMO,但是,如果你考虑上面提到的模式,那么,无论你的项目范围如何(看起来你打算制作一个游戏,不是一个小任务)你将能够继续控制较低级别的依赖。正如@Loc指出的那样,依赖注入'低等级对象应该在黑暗中保持'就任何具体实施而言,就它们所消耗的数据而言;这是(应该)保留给顶级层次结构。 '编程到接口,而不是实现'。
似乎你对此有一个概念。让我指出我在这一点上看到可能的错误。实际上已经是一对夫妇了,你专注于沙粒。 "子弹"你并没有达到这样的微不足道的目的,除非是一个警示标志,你现在即将失去对更高级别依赖的控制。
无论您是否能够看到它,细粒度部分都可以而且应该在更高级别处理。我会提出几点建议。 @Loc已经提到了最佳实践' Constructor Injection'松散的资格,更好地查找这个术语'依赖注入'。
以子弹为例因为它们已经出现在你的范围内。复合模式旨在处理许多不同但相关的第一类对象,例如命令。在迭代器和访问者模式之间,您可以将所有预先实例化的命令以及未来的实例存储在动态数据结构中,甚至是链接列表或二进制搜索树。此时忘记了战略 模式,一些可能的场景是一回事,但是从一开始就编写自适应接口是没有意义的。
另一件事,我认为没有迹象表明你是从一个级别产生射弹,我的意思是子弹。然而,即使只是跟踪武器配置和容量(int项目)(我只是猜测这是射弹数量必要变化的原因)的问题,使用堆栈结构或取决于什么实际情况是;循环队列。如果您实际上正在从工厂产生射弹,或者如果您将来决定使用,则您已准备好利用对象池;事实证明,这是出于这种明确的考虑。
并不是说这里的任何人都这样做了,但我发现特别是因为有人建议可以错误处理或忽视任何既定(特别是GoF)设计模式背后的特定动机。如果您发现自己必须修改GoF设计模式,那么您使用的是错误的模式。只是说'
P.S。如果你绝对必须,为什么不相反,使用模板解决方案,而不是改变有意识的特定接口设计;
答案 3 :(得分:-1)
此模式的目的是允许定义操作,并在以后执行一次或多次。
您提供的代码是此模式的一个很好的示例:您定义了“重新加载”操作,该操作会向gun
收取bullets=10
个弹药的费用。
现在,如果您决定修改此代码以添加bullets
作为参数,那么您将完全失去此模式的目的,因为您必须每次都定义弹药数量。
ReloadWeaponCommand
个实例,其值不同bullets
。然后,您可能必须使用其他模式(例如Strategy)来切换命令。