Patró estratègia

De Viquipèdia
Dreceres ràpides: navegació, cerca
Aquest article tracta sobre informàtica. Vegeu-ne altres significats a «Estratègia».

Estratègia (Strategy en anglès) és un patró de disseny per a desenvolupar programari.

El patró Strategy permet mantenir un conjunt d'algorismes amb l'objectiu que el client pugui escollir el que més li convingui i intercanviar-lo segons les seves necessitats.

Els diferents algorismes s'encapçalen i el client treballa contra un objecte Context. Com hem dit, el client pot escollir l'algorisme que prefereix entre tots els disponibles, o pot ser el mateix objecte Context el que esculli el més adequat per a cada situació.

Qualsevol programa que ofereixi un servei o funció determinada, que pugui ser realitzada de diferents formes, és candidat a usar el patró Strategy. Pot haver-hi diferents estratègies i qualsevol d'elles pot ser intercanviada per una altra en qualsevol moment, inclús en temps d'execució.

Diagrama[modifica | modifica el codi]

Diagrama de classes del patró Strategy

Exemples de Codi[modifica | modifica el codi]

C++[modifica | modifica el codi]

#include <iostream>
 
using namespace std;
 
class StrategyInterface
{
    public:
        virtual void execute() = 0;
};
 
class ConcreteStrategyA: public StrategyInterface
{
    public:
        virtual void execute()
        {
            cout << "Called ConcreteStrategyA execute method" << endl;
        }
};
 
class ConcreteStrategyB: public StrategyInterface
{
    public:
        virtual void execute()
        {
            cout << "Called ConcreteStrategyB execute method" << endl;
        }
};
 
class ConcreteStrategyC: public StrategyInterface
{
    public:
        virtual void execute()
        {
            cout << "Called ConcreteStrategyC execute method" << endl;
        }
};
 
class Context
{
    private:
        StrategyInterface *_strategy;
 
    public:
        Context(StrategyInterface *strategy):_strategy(strategy)
        {
        }
 
        void set_strategy(StrategyInterface *strategy)
        {
            _strategy = strategy;
        }
 
        void execute()
        {
            _strategy->execute();
        }
};
 
int main(int argc, char *argv[])
{
    ConcreteStrategyA concreteStrategyA;
    ConcreteStrategyB concreteStrategyB;
    ConcreteStrategyC concreteStrategyC;
 
    Context contextA(&concreteStrategyA);
    Context contextB(&concreteStrategyB);
    Context contextC(&concreteStrategyC);
 
    contextA.execute();
    contextB.execute();
    contextC.execute();
 
    contextA.set_strategy(&concreteStrategyB);
    contextA.execute();
    contextA.set_strategy(&concreteStrategyC);
    contextA.execute();
 
    return 0;
}

Java[modifica | modifica el codi]

public class Main {	
	public static void main(String args[])
	{
		//Inicialment utilitzem l'estratègia A
		Strategy estrategia_inicial = new StrategyA();
		Context context = new Context(estrategia_inicial);
		context.some_method();
 
		//En un moment determinat decidim utilitzar l'estratègia B
		Strategy estrategia2 = new StrategyB();
		context.setStrategy(estrategia2);
		context.some_method();
 
		//Finalment tornem a utilitzar l'estratègia A
		context.setStrategy(estrategia_inicial);
		context.some_method();
 
		/** Output:
		 * Estem utilitzant el comportament de l'estrategia A
		 * Estem utilitzant el comportament de l'estrategia B
		 * Estem utilitzant el comportament de l'estrategia A
		 **/
	}
}
 
 
public class Context {
	Strategy c;
 
	public Context( Strategy c )
	{
		this.c = c;
	}
 
	public void setStrategy(Strategy c) {
		this.c = c;
	}
 
	//Mètode que utilitzarà una estratègia 'c'
	public void some_method()
	{
		c.Behaviour();
	}
}
 
public class StrategyA implements Strategy{
	@Override
	public void Behaviour() {
		System.out.println("Estem utilitzant el comportament de l'estrategia A");
	}
}
 
public class StrategyB implements Strategy{
	@Override
	public void Behaviour() {
		System.out.println("Estem utilitzant el comportament de l'estrategia B");
	}
}

Python[modifica | modifica el codi]

Pythonja el té implementat i no cal programar-lo explícitament. Aquí tenim un exemple amb una GUI:

class Button:
    """A very basic button widget."""
    def __init__(self, submit_func, label):
        self.on_submit = submit_func   # Set the strategy function directly
        self.label = label
 
# Creem dos objecte amb diferents estratègies
button1 = Button(sum, "Add 'em")
button2 = Button(lambda nums: " ".join(map(str, nums)), "Join 'em")
 
# Provem cada button
numbers = range(1, 10) # A list of numbers 1 through 9
print button1.on_submit(numbers) # displays "45"
print button2.on_submit(numbers) # displays "1 2 3 4 5 6 7 8 9"

C# 3.0[modifica | modifica el codi]

In C# 3.0, with lambda expressions we can do something similar to the Python example above.

using System;
using System.Collections.Generic;
using System.Linq;
 
class Program
{
  static void Main(string[] args)
  {
    var button1 = new MyButton((x) => x.Sum().ToString(), "Add 'em");
    var button2 = new MyButton((x) => string.Join(" ", x.Select(y => y.ToString()).ToArray()), "Join 'em");
 
    var numbers = Enumerable.Range(1, 10);
    Console.WriteLine(button1.Submit(numbers));
    Console.WriteLine(button2.Submit(numbers));
 
    Console.ReadLine();
  }
 
  public class MyButton
  {
    private readonly Func<IEnumerable<int>, string> submitFunction;
    public string Label { get; private set; }
 
    public MyButton(Func<IEnumerable<int>, string> submitFunction, string label)
    {
        this.submitFunction = submitFunction;
        Label = label;
    }
 
    public string Submit(IEnumerable<int> data)
    {
        return submitFunction(data);
    }
  }
}

C#[modifica | modifica el codi]

using System;
 
namespace Wikipedia.Patterns.Strategy
{
  // MainApp aplicació de prova
  class MainApp
  {
    static void Main()
    {
      Context context;
 
      // Three contexts following different strategies
      context = new Context(new ConcreteStrategyA());
      context.Execute();
 
      context = new Context(new ConcreteStrategyB());
      context.Execute();
 
      context = new Context(new ConcreteStrategyC());
      context.Execute();
 
    }
  }
 
  // La classe que implementa un "concrete strategy" hauria d'implementar això
  // La classe "context" usa això per cridar a un "concrete strategy"
  interface IStrategy
  {
    void Execute();
  }
 
  // Implements the algorithm using the strategy interface
  class ConcreteStrategyA : IStrategy
  {
    public void Execute()
    {
      Console.WriteLine( "Called ConcreteStrategyA.Execute()" );
    }
  }
 
  class ConcreteStrategyB : IStrategy
  {
    public void Execute()
    {
      Console.WriteLine( "Called ConcreteStrategyB.Execute()" );
    }
  }
 
  class ConcreteStrategyC : IStrategy
  {
    public void Execute()
    {
      Console.WriteLine( "Called ConcreteStrategyC.Execute()" );
    }
  }
 
  // Configurat amb un objecte ConcreteStrategy object i manté una referencia a un Strategy object
  class Context
  {
    IStrategy strategy;
 
    // Constructor
    public Context(IStrategy strategy)
    {
      this.strategy = strategy;
    }
 
    public void Execute()
    {
      strategy.Execute();
    }
  }
}

ActionScript 3[modifica | modifica el codi]

//invoked from application.initialize
private function init() : void
{
    var context:Context;
 
    context = new Context( new ConcreteStrategyA() );
    context.execute();
 
    context = new Context( new ConcreteStrategyB() );
    context.execute();
 
    context = new Context( new ConcreteStrategyC() );
    context.execute();
}
 
package org.wikipedia.patterns.strategy
{
    public interface IStrategy
    {
	function execute() : void ;
    }
}
 
package org.wikipedia.patterns.strategy
{
    public final class ConcreteStrategyA implements IStrategy
    {
	public function execute():void
	{
	 trace( "ConcreteStrategyA.execute(); invoked" );
	}
    }
}
 
package org.wikipedia.patterns.strategy
{
    public final class ConcreteStrategyB implements IStrategy
    {
	public function execute():void
	{
	 trace( "ConcreteStrategyB.execute(); invoked" );
	}
    }
}
 
package org.wikipedia.patterns.strategy
{
    public final class ConcreteStrategyC implements IStrategy
    {
	public function execute():void
	{
	 trace( "ConcreteStrategyC.execute(); invoked" );
	}
    }
}
 
package org.wikipedia.patterns.strategy
{
   public class Context
   {
	private var strategy:IStrategy;
 
	public function Context(strategy:IStrategy)
	{
	 this.strategy = strategy;
	}
 
	public function execute() : void
	{ 
             strategy.execute();
	}
    }
}

PHP[modifica | modifica el codi]

<?php
class StrategyExample {
    public function __construct() {
        $context = new Context(new ConcreteStrategyA());
        $context->execute();
 
        $context = new Context(new ConcreteStrategyB());
        $context->execute();
 
        $context = new Context(new ConcreteStrategyC());
        $context->execute();
    }
}
 
interface IStrategy {
    public function execute();
}
 
class ConcreteStrategyA implements IStrategy {
    public function execute() {
        echo "Called ConcreteStrategyA execute method\n";
    }
}
 
class ConcreteStrategyB implements IStrategy {
    public function execute() {
        echo "Called ConcreteStrategyB execute method\n";
    }
}
 
class ConcreteStrategyC implements IStrategy {
    public function execute() {
        echo "Called ConcreteStrategyC execute method\n";
    }
}
 
class Context {
    var $strategy;
 
    public function __construct(IStrategy $strategy) {
        $this->strategy = $strategy;
    }
 
    public function execute() {
        $this->strategy->execute();
    }
}
 
new StrategyExample;
?>

Perl[modifica | modifica el codi]

Perl ja el té implementat i no cal programar-lo explícitament:

sort { lc($a) cmp lc($b) } @items

El patró d'estratègia pot estar implementat formalment amb Moose:

package Strategy;
use Moose::Role;
requires 'execute';
 
 
package FirstStrategy;
use Moose;
with 'Strategy';
 
sub execute {
    print "Called FirstStrategy->execute()\n";
}
 
 
package SecondStrategy;
use Moose;
with 'Strategy';
 
sub execute {
    print "Called SecondStrategy->execute()\n";
}
 
 
package ThirdStrategy;
use Moose;
with 'Strategy';
 
sub execute {
    print "Called ThirdStrategy->execute()\n";
}
 
 
package Context;
use Moose;
 
has 'strategy' => (
    is => 'rw',
    does => 'Strategy',
    handles => [ 'execute' ],  # automatic delegation
);
 
 
package StrategyExample;
use Moose;
 
# Moose's constructor
sub BUILD {
    my $context;
 
    $context = Context->new(strategy => 'FirstStrategy');
    $context->execute;
 
    $context = Context->new(strategy => 'SecondStrategy');
    $context->execute;
 
    $context = Context->new(strategy => 'ThirdStrategy');
    $context->execute;
}
 
 
package main;
 
StrategyExample->new;

Enllaços externs[modifica | modifica el codi]

A Wikimedia Commons hi ha contingut multimèdia relatiu a: Patró estratègia Modifica l'enllaç a Wikidata