当我们需要修改上下文类时实现策略模式

时间:2014-09-29 15:56:01

标签: javascript design-patterns strategy-pattern

我有一个包含一系列位(“基因”)的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';
  });
};

2 个答案:

答案 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是私有实现细节,那么是,它反对封装从外部修改这个私有属性。

  

我正在阅读一些争论,即策略模式不应该修改调用它的上下文的状态

我认为这是一种“良好做法”而非严格要求。将策略视为仅使用对象而不是修改它的东西更容易。