Vés al contingut

Patró estratègia

De Viki.cat
(S'ha redirigit des de: Strategy (patró de disseny))

<templatestyles src="Metacaixa enllaç de desambiguació/styles.css" />

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 mes 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

Diagrama de classes del patró Strategy

Exemples de Codi

C++

<source lang="cpp">

  1. 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;

} </source>

Java

<source lang="java">

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


</source>

Python

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

<source lang="python"> 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
  1. Creem dos objecte amb diferents estrategies

button1 = Button(sum, "Add 'em") button2 = Button(lambda nums: " ".join(map(str, nums)), "Join 'em")

  1. 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" </source>

C# 3.0

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

<source lang="csharp"> 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);
   }
 }

} </source>

C#

<source lang="csharp">

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

}

</source>

ActionScript 3

<source lang="actionscript">

//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();

}

   }

}

</source>

PHP

<source lang="php"> <?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; ?>

</source>

Perl

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

<source lang="perl"> sort { lc($a) cmp lc($b) } @items </source>

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

<source lang="perl"> 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;

  1. 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; </source>

Enllaços externs

Plantilla:Sister