A számítógép-programozásban a stratégia minta (vezérelv mintaként is ismert) egy szoftvertervezési minta, amely lehetővé teszi, hogy egy algoritmus viselkedését a futás során válasszuk meg. A stratégia minta meghatározza az algoritmusok egy családját, egységbe foglal minden algoritmust, és a családon belül cserélhetővé teszi ezeket az algoritmusokat.
A stratégia segítségével az algoritmus az őt használó kliensektől függetlenül változhat, miután az megtette a beállításokat. A stratégia minta az egyike a Design Patterns könyvbenEric Freeman, Elisabeth Freeman, Kathy Sierra and Bert Bates, Head First Design Patterns, First Edition, Chapter 1, Page 24, O'Reilly Media, Inc, 2004. szereplő mintáknak, mely népszerűsítette a minták használatát a szoftvertervezés folyamatában.
Például egy osztály, mely bejövő adatokat érvényesít, stratégiai mintát használhat a validációs algoritmus kiválasztására a bejövő adat típusa, az adat forrása, felhasználói választás vagy más megkülönböztető tényező alapján. Ezek a tényezők nem minden esetben ismertek a futtatás előtt, és szükségessé válhat radikálisan eltérő érvényesítési módok használata. A validációs stratégiákat, melyeket külön egységbe zártunk a validáló objektumoktól, a rendszer más területéről származó validációs objektumok (vagy akár más rendszerek) is használhatják kódduplikáció nélkül.
A programozási nyelvekben alapvető követelmény, hogy képes legyen az adatstruktúrában található kódra mutató referenciák tárolására és elérésére. Ennek elérését olyan mechanizmusok segítik, mint a natív függvény pointerek, elsődleges típusú függvények, osztályok vagy osztály példányok az objektumorientált programozási nyelvekben, vagy mint a nyelv implementációs belső tárolójának elérése önelemzés (reflexió, reflection) segítségével.
Felépítése
Példa C# namespace IVSR.Designpattern.Strategy { //A stratégiák interfésze public interface ICalculateInterface { int Calculate(int value1, int value2);
//stratégiák //Stratégia 1: Mínusz class Minus : ICalculateInterface { public int Calculate(int value1, int value2) { return value1 - value2;
//Stratégia 2: Plusz class Plus : ICalculateInterface { public int Calculate(int value1, int value2) { return value1 + value2;
//A kliens class CalculateClient { private ICalculateInterface calculateStrategy;
//Konstruktor: az interfészhez rendeli a stratégiá public CalculateClient(ICalculateInterface strategy) { this.calculateStrategy = strategy;
//Stratégia végrehajtása public int Calculate(int value1, int value2) { return calculateStrategy.Calculate(value1, value2);
//Inicializálás protected void Page_Load(object sender, EventArgs e) { CalculateClient minusClient = new CalculateClient(new Minus()); Response.Write("<br />Minus: " + minusClient.Calculate(7, 1).ToString());
CalculateClient plusClient = new CalculateClient(new Plus()); Response.Write("<br />Plus: " + plusClient.Calculate(7, 1).ToString());
Java A következő példa Java programozási nyelvben íródott. package javaapplication8;
import java.util.ArrayList; import java.util.List;
// Minta a Stratégia tervezési mintára public class JavaApplication8 { public static void main(String[] args){ Customer a = new Customer(); a.setStrategy(new NormalStrategy());
// Normál számlázás a.add(1.2,1);
// Happy Hour inditása a.setStrategy(new HappyHourStrategy()); a.add(1.2,2);
// Új ügyfél Customer b = new Customer(); b.setStrategy(new HappyHourStrategy()); b.add(0.8,1); // Az ügyfél fizet a.printBill();
// Happy Hour vége b.setStrategy(new NormalStrategy()); b.add(1.3,2); b.add(2.5,1); b.printBill();
class Customer{ private List<Double> drinks; private BillingStrategy strategy;
public Customer() { this.drinks = new ArrayList<Double>();
// Új elem az étlapra public void add(double price, int quantity){ drinks.add(price*quantity);
// Számla kifizetése public void printBill(){ System.out.println("Total due: " + strategy.sum(drinks)); drinks.clear();
// Stratégia beállítása public void setStrategy(BillingStrategy strategy) { this.strategy = strategy;
interface BillingStrategy{ // A fogyasztott italok összegzett ára public double sum(List<Double> drinks); }
// Normál számlátási stratégia (változatlan árakon) class NormalStrategy implements BillingStrategy{ public double sum(List<Double> drinks) { double sum = 0; for(Double i : drinks){ sum += i;
return sum;
// Happy hour stratégia(10% engedmény) class HappyHourStrategy implements BillingStrategy{ public double sum(List<Double> drinks) { double sum = 0; for(Double i : drinks){ sum += i;
return sum*0.9;
Egy sokkal egyszerűbb példa a 'modern Javában' (Java 8 vagy újabb) a lambdák használataWikikönyvek: Computer Science Design Patterns/Strategy
Stratégia és a nyílt-zárt alapelv
A stratégia minta szerint az osztály viselkedését nem szabad örökítenünk. Ehelyett egységbe kell zárnunk interfészek alkalmazásával. Például vegyünk egy Autó osztályt. Az Autó két lehetséges funkciója a fék és a gyorsulás.
Mivel a gyorsulás és a fék viselkedése gyakran eltérő a különböző modellek esetén, az általános felfogás szerint ezeket a viselkedéseket külön osztályokba sorolnánk, amelyek ugyanazt az interfészt valósítják meg, a kód öröklésének kiiktatásával. Ennek a megközelítésnek viszont jelentős hátrányai vannak: minden egyes új autómodellhez újra kell értelmezni a gáz és a fék viselkedését. Ezen viselkedések kezelésével járó munka a modellek számának a növekedésével jelentősen megnő, és kód-duplikációhoz vezethet. Továbbá nem egyszerű feladat meghatározni minden modell pontos viselkedését anélkül, hogy a bennük megírt kódot külön megvizsgálnunk.
A stratégia minta öröklés helyett kompozíciót használ. Itt a viselkedést különálló interfészként és specifikus osztályokként definiáljuk, melyek ezeket az interfészeket valósítják meg. Ez lehetővé teszi a viselkedés és a viselkedést alkalmazó osztály jobb szétválasztását. A viselkedést anélkül tudjuk megváltoztatni, hogy betörnénk az osztályt, ami használja, illetve az osztályok lecserélhetik viselkedésüket a konkrét megvalósítás megváltoztatása által, anélkül hogy a kódot jelentőségteljesen megváltoztatnánk. A viselkedés változhat futási időben és tervezési időben is. Például az autó objektum fék viselkedését megváltoztathatjuk BrakeWithABS() -ről Brake() -re azáltal, hogy megváltoztatjuk a brakeBehavior tagot az alábbi módon:
brakeBehavior = new Brake();
/* Algoritmusok egységbezárt családja * Interfész és annak megvalósításai */ public interface IBrakeBehavior { public void brake(); }
public class BrakeWithABS implements IBrakeBehavior { public void brake() { System.out.println("Brake with ABS applied");
public class Brake implements IBrakeBehavior { public void brake() { System.out.println("Simple Brake applied");
/* Kliens mely a fenti algoritmusokat váltakozva használhatja */ public abstract class Car { protected IBrakeBehavior brakeBehavior;
public void applyBrake() { brakeBehavior.brake();
public void setBrakeBehavior(IBrakeBehavior brakeType) { this.brakeBehavior = brakeType;
/* 1. Kliens mely a fenti Bake algoritmust használja konstruktorban */ public class Sedan extends Car { public Sedan() { this.brakeBehavior = new Brake();
/* 2. Kliens mely a BrakeWithABS algoritmust használja konstruktorban */ public class SUV extends Car { public SUV() { this.brakeBehavior = new BrakeWithABS();
/* Használunk egy PéldaAutót (carExample) */ public class CarExample { public static void main(String[] args) { Car sedanCar = new Sedan(); sedanCar.applyBrake(); // "Brake" osztály meghívása
Car suvCar = new SUV(); suvCar.applyBrake(); // "BrakeWithABS" osztály meghívása
// fék viselkedésének dinamikus beallítása suvCar.setBrakeBehavior( new Brake() ); suvCar.applyBrake(); // "Brake" osztály meghívása
Ez a megoldás nagyobb rugalmasságot biztosít és összhangban van a Nyitva-Zárt Alapelvvel, mely kimondja, hogy az osztályoknak nyitottnak kell lenni a kiterjesztésekre, de zártnak a módosításokra.
Források
További információk Strategy Pattern in UML (Spanish, but english model)
The Strategy Pattern from the Net Objectives Repository Strategy Pattern for Java article Strategy Pattern for CSharp article Strategy pattern in UML and in LePUS3 (a formal modelling notation) Refactoring: Replace Type Code with State/Strategy
Fordítás
Kategória:Programtervezési minták Kategória:Java-kódpéldák Kategória:C Sharp-kódpéldák