Dan Tang
Dan Tang

Reputation: 1343

Implementing strategy pattern when we need to modify the context class

I have a Genome class that contains an array of bits ("genes"), and I would like to implement different mutation methods to change the genes. I'm currently implementing the mutation method using a Strategy Pattern, but the mutation method changes the Genome class directly.

Is this consider breaking encapsulation if I pass in the genes array into the Strategy and it modifies the array directly (naiveMutationStrategy)? I was reading some arguments that the Strategy pattern should not modify the state of the context calling it?

What if I directly passed in the Genome class (naiveMutationStrategy2) - I assume this is a no-no since the strategy pattern shouldn't store a reference to the context object?

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

Upvotes: 1

Views: 581

Answers (2)

Bergi
Bergi

Reputation: 664970

I'm currently implementing the mutation method using a Strategy Pattern

Good idea, but don't try to reproduce the pattern you've learned for a class-based language too closely. Your constructor functions for the strategies are empty - they're unnecessary (unless you want some kind of "StrategyFactory"). Even those prototype objects with their methods are unncessary, they have only a single method.

JavaScript is a functional language, with first-class function objects. In a functional language, a "strategy" is just a function. Pass functions, not Strategy instances.

but the mutation method changes the Genome class directly.

Not really - it does not assign to the properties of Genome instances. All it does is to mutate the arguments that it got passed, which is (more or less) fine.

Is this consider breaking encapsulation if I pass in the genes array into the Strategy and it modifies the array directly (naiveMutationStrategy)?

No. The contracts are "the strategy expects an array argument" and "the strategy might modify its argument" - if you don't like the latter than use a different one. Really breaking encapsulation would be if the strategy got passed the Genome instance and would modify its properties from outside. As long your mutate method controls what is going on, I can't see a problem.

I was reading some arguments that the Strategy pattern should not modify the state of the context calling it?

Yes, it certainly is a good idea. If the genes were immutable and the strategy did create a new sequence of genes, your code would benefit.

_.each(genes, function(element) {
  if (element === '0') {
    element = '1'
  } else element = '0';
});

Notice that you're actually not mutating anything here. element is a local variable, not a reference to the array element. If you'd really wanted to mutate the array, you'd use

for (var i=0; i<genes.length; i++)
  if (genes[i] === '0')
    genes[i] = '1'
  else
    genes[i] = '0';

and if you wanted to create a new sequence, you'd use

return _.map(genes, function(element) {
  return (element === '0') ? '1' : '0';
});

Upvotes: 1

Wiktor Zychla
Wiktor Zychla

Reputation: 48279

Is this consider breaking encapsulation

I don't think so but it depends on whether or not you want genes to be considered as a part of a public genome interface (contract) or not. In other words, if the world is aware that genome has genes then it is not against encapsulation to access this public property. If genes is a private implementation detail, then yes, it is against encapsulation to modify this private property from outside.

I was reading some arguments that the Strategy pattern should not modify the state of the context calling it

I would consider this as a "good practice" rather than strict requirement. It is just easier to think about strategy as something that only uses the object rather than modify it.

Upvotes: 0

Related Questions