Patró 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ó.
Taula de continguts |
Diagrama[modifica]
Exemples de Codi[modifica]
C++[modifica]
#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]
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]
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 estrategies 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]
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]
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]
//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]
<?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]
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]
| A Wikimedia Commons hi ha contingut multimèdia relatiu a: Patró estratègia |
- The Strategy Pattern from the Net Objectives Repository (anglès)
- Article sobre el patró d'estratègia per Java (anglès)
- El patró d'estratègia en UML i en LePUS3 (una notació de modelatge formal) (anglès)
- Data & object factory (anglès)
- Refactoring: Replace Type Code with State/Strategy (anglès)
- Jt Patró de J2EE orientat a Framework (anglès)
- Patró d'Estratègia amb un twist! (anglès)
|
|||||||||||