Patró estratègia

From Wikipedia, the free encyclopedia

Remove ads

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

Aquest article tracta sobre informàtica. Vegeu-ne altres significats a «Estratègia».

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ó.

Remove ads

Diagrama

Thumb

Exemples de Codi

C++

#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

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'estratègia A
		 * Estem utilitzant el comportament de l'estratègia B
		 * Estem utilitzant el comportament de l'estratègia 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'estratègia A");
	}
}

public class StrategyB implements Strategy{
	@Override
	public void Behaviour() {
		System.out.println("Estem utilitzant el comportament de l'estratègia B");
	}
}

Python

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

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#

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

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

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

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;
Remove ads

Enllaços externs

  • Refactoring: Replace Type Code with State/Strategy (anglès)
Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.

Remove ads