我有一个包含一系列位(“基因”)的Genome类,我想实现不同的突变方法来改变基因。我目前正在使用策略模式实现变异方法,但是变异方法直接改变了Genome类。
如果我将基因数组传入策略并直接修改数组(naiveMutationStrategy),是否考虑打破封装?我正在阅读一些论点,即策略模式不应该修改调用它的上下文的状态吗?
如果我直接传入Genome类(naiveMutationStrategy2)怎么办?我认为这是禁忌,因为策略模式不应该存储对上下文对象的引用?
function Genome(genes, mutationStrategy) {
this.genes = genes; //an array
this.mutationStrategy = mutationStategy;
}
Genome.prototype.mutate = function() {
this.mutationStategy.execute(this.genes);
}
function naiveMutationStrategy() {};
//converts '1' into '0' and vice versa
mStrategy.prototype.execute = function(genes) {
_.each(genes, function(element) {
if (element === '0') {
element = '1'
} else element = '0';
});
};
function naiveMutationStrategy2() {};
//converts '1' into '0' and vice versa
naiveMutationStrategy2.prototype.execute = function(genome) {
_.each(genome.genes, function(element) {
if (element === '0') {
element = '1'
} else element = '0';
});
};
答案 0 :(得分:1)
我目前正在使用策略模式实现变异方法
好主意,但不要尝试过于密切地重现您为基于类的语言所学习的模式。策略的构造函数是空的 - 它们是不必要的(除非你想要某种“StrategyFactory”)。即使那些带有方法的原型对象也是不必要的,它们只有一种方法。
JavaScript是一种函数式语言,具有一流的函数对象。在功能语言中,“策略”只是一种功能。传递函数,而不是Strategy
个实例。
但是变异方法直接改变了Genome类。
不是 - 它没有分配给Genome
个实例的属性。它所做的就是改变它传递的参数,这或多或少都很好。
如果我将基因数组传入策略并直接修改数组(naiveMutationStrategy),是否考虑打破封装?
没有。合同是“策略期望数组参数”和“策略可能修改其参数” - 如果您不喜欢后者而不是使用不同的参数。如果策略通过了Genome
实例并且将从外部修改其属性,那么真正打破封装将是真的。只要您的mutate
方法控制正在发生的事情,我就看不到问题。
我正在阅读一些争论,即策略模式不应该修改调用它的上下文的状态?
是的,这当然是个好主意。如果genes
是不可变的并且策略确实创建了一个新的基因序列,那么您的代码将会受益。
_.each(genes, function(element) { if (element === '0') { element = '1' } else element = '0'; });
请注意,你实际上并没有在这里改变任何东西。 element
是局部变量,不是对数组元素的引用。如果你真的想改变数组,你可以使用
for (var i=0; i<genes.length; i++)
if (genes[i] === '0')
genes[i] = '1'
else
genes[i] = '0';
如果你想创建一个新序列,你可以使用
return _.map(genes, function(element) {
return (element === '0') ? '1' : '0';
});
答案 1 :(得分:0)
这是否考虑打破封装
我不这么认为,但这取决于您是否希望genes
被视为公共genome
接口(合同)的一部分。换句话说,如果世界意识到genome
具有genes
,则不会反对封装来访问此公共属性。如果genes
是私有实现细节,那么是,它反对封装从外部修改这个私有属性。
我正在阅读一些争论,即策略模式不应该修改调用它的上下文的状态
我认为这是一种“良好做法”而非严格要求。将策略视为仅使用对象而不是修改它的东西更容易。