Стратегия үлгісі - Strategy pattern

Жылы компьютерлік бағдарламалау, стратегия үлгісі (деп те аталады саясат үлгісі) Бұл мінез-құлық бағдарламалық жасақтаманың дизайны таңдауға мүмкіндік беретін алгоритм жұмыс кезінде. Тікелей бір алгоритмді іске асырудың орнына, код алгоритмдер отбасында қолданылатын жұмыс уақытының нұсқауларын алады.[1]

Стратегия алгоритмнің оны қолданатын клиенттерден тәуелсіз өзгеруіне мүмкіндік береді.[2] Стратегия - әсерлі кітапқа енген заңдылықтардың бірі Дизайн үлгілері Гамма және басқалар[3] бұл икемді және қайта пайдалануға болатын бағдарламалық жасақтаманы қалай жобалау керектігін сипаттау үшін дизайн үлгілерін пайдалану тұжырымдамасын кеңінен насихаттады. Жұмыс уақытына дейін қандай алгоритмді қолдану туралы шешім қабылдауды кейінге қалдыру қоңырау кодын икемді және қайта пайдалануға мүмкіндік береді.

Мысалы, кіріс деректерін тексеруді жүзеге асыратын класс деректердің түріне, деректер көзіне, пайдаланушының таңдауына немесе басқа кемсітушілік факторларына байланысты тексеру алгоритмін таңдау үшін стратегия үлгісін қолдана алады. Бұл факторлар жұмыс уақытына дейін белгісіз және олардан түбегейлі әр түрлі тексеру жүргізу қажет болуы мүмкін. Тексеру объектісінен бөлек салынған валидация алгоритмдерін (стратегияларын) жүйенің әр түрлі аймағындағы (немесе тіпті әр түрлі жүйелердегі) басқа валидатор объектілері пайдалана алады. кодтың қайталануы.

Әдетте, стратегия үлгісі деректер құрылымындағы кейбір кодтарға сілтемені сақтайды және оны алады. Бұған жергілікті сияқты тетіктер арқылы қол жеткізуге болады функция көрсеткіші, бірінші дәрежелі функция, сыныптар немесе сынып даналары объектіге бағытталған бағдарламалау тілдер, немесе тілдік енгізудің ішкі жадына код арқылы қол жеткізу шағылысу.

Құрылым

UML сыныбы және реттілік диаграммасы

Стратегияны жобалау үлгісіне арналған UML сыныбы мен реттілік диаграммасының үлгісі. [4]

Жоғарыда UML сынып диаграммасы, Мәтінмән класс алгоритмді тікелей жүзеге асырмайды. Мәтінмән сілтеме жасайды Стратегия алгоритмді орындауға арналған интерфейс (strategy.algorithm ()) жасайды Мәтінмән алгоритм қалай жүзеге асырылатынынан тәуелсіз Стратегия1 және Стратегия2 сыныптар Стратегия интерфейс, яғни алгоритмді жүзеге асырады (инкапсуляциялайды).
The UML реттілік диаграммасы жұмыс уақытының өзара әрекеттесуін көрсетеді: Мәтінмән объект алгоритмді басқасына тапсырады Стратегия нысандар. Біріншіден, Мәтінмән қоңыраулар алгоритм () үстінде Стратегия1 алгоритмді орындайтын және нәтижені қайтаратын объект Мәтінмән. Содан кейін, Мәтінмән өзінің стратегиясын өзгертеді және шақырады алгоритм () үстінде Стратегия2 алгоритмді орындайтын және нәтижені қайтаратын объект Мәтінмән.

Сынып диаграммасы

Стратегия үлгісі UML

[5]

Стратегия үлгісі LePUS3 (аңыз )

Мысал

C #

Келесі мысал C #.

қоғамдық сынып StrategyPatternWiki{    қоғамдық статикалық жарамсыз Негізгі(Жол[] доға)    {        // Стратегияларды дайындаңыз        var қалыпты стратегия    = жаңа NormalStrategy();        var happyHourStrategy = жаңа HappyHourStrategy();        var бірінші тұтынушы = жаңа Клиенттік шот(қалыпты стратегия);        // Қалыпты есеп айырысу        бірінші тұтынушы.Қосу(1.0, 1);        // Бақытты сағатты бастаңыз        бірінші тұтынушы.Стратегия = happyHourStrategy;        бірінші тұтынушы.Қосу(1.0, 2);        // Жаңа тұтынушы        Клиенттік шот екінші тұтынушы = жаңа Клиенттік шот(happyHourStrategy);        екінші тұтынушы.Қосу(0.8, 1);        // Тапсырыс беруші төлейді        бірінші тұтынушы.Басып шығару();        // Бақытты сағатты аяқтаңыз        екінші тұтынушы.Стратегия = қалыпты стратегия;        екінші тұтынушы.Қосу(1.3, 2);        екінші тұтынушы.Қосу(2.5, 1);        екінші тұтынушы.Басып шығару();    }}// CustomerBill класс атауы ретінде, өйткені ол клиенттің шотына қатыстысынып Клиенттік шот{    жеке IList<екі есе> сусындар;    // Стратегияны алу / орнату    қоғамдық IBillingStrategy Стратегия { алу; орнатылды; }    қоғамдық Клиенттік шот(IBillingStrategy стратегия)    {        бұл.сусындар = жаңа Тізім<екі есе>();        бұл.Стратегия = стратегия;    }    қоғамдық жарамсыз Қосу(екі есе баға, int саны)    {        бұл.сусындар.Қосу(бұл.Стратегия.GetActPrice(баға * саны));    }    // Вексельді төлеу    қоғамдық жарамсыз Басып шығару()    {        екі есе сома = 0;        әрқайсысы үшін (var drinkCost жылы бұл.сусындар)        {            сома += drinkCost;        }        Консоль.WriteLine($«Барлығы: {sum}.»);        бұл.сусындар.Таза();    }}интерфейс IBillingStrategy{    екі есе GetActPrice(екі есе шикізатБағасы);}// Қалыпты есеп айырысу стратегиясы (өзгермеген баға)сынып NormalStrategy : IBillingStrategy{    қоғамдық екі есе GetActPrice(екі есе шикізатБағасы) => шикізатБағасы;}// Бақытты сағат стратегиясы (50% жеңілдік)сынып HappyHourStrategy : IBillingStrategy{    қоғамдық екі есе GetActPrice(екі есе шикізатБағасы) => шикізатБағасы * 0.5;}

Java

Келесі мысал Java.

импорт java.util.ArrayList;интерфейс BillingStrategy {    // Жылжымалы нүктені дөңгелектеу қателігін болдырмау үшін бағаны центпен пайдаланыңыз    int getActPrice(int шикізатБағасы);      // Қалыпты есеп айырысу стратегиясы (өзгермеген баға)    статикалық BillingStrategy қалыпты стратегия() {        қайту шикізатБағасы -> шикізатБағасы;    }      // Бақытты сағат стратегиясы (50% жеңілдік)    статикалық BillingStrategy happyHourStrategy() {        қайту шикізатБағасы -> шикізатБағасы / 2;    }}сынып Клиенттік шот {    жеке ақтық Тізім<Бүтін> сусындар = жаңа ArrayList<>();    жеке BillingStrategy стратегия;    қоғамдық Клиенттік шот(BillingStrategy стратегия) {        бұл.стратегия = стратегия;    }    қоғамдық жарамсыз қосу(int баға, int саны) {        бұл.сусындар.қосу(бұл.стратегия.getActPrice(баға*саны));    }    // Вексельді төлеу    қоғамдық жарамсыз басып шығару() {        int сома = бұл.сусындар.ағын().mapToInt(v -> v).сома();        Жүйе.шығу.println(«Барлығы:» + сома);        бұл.сусындар.анық();    }    // Стратегияны белгілеңіз    қоғамдық жарамсыз setStrategy(BillingStrategy стратегия) {        бұл.стратегия = стратегия;    }}қоғамдық сынып StrategyPattern {    қоғамдық статикалық жарамсыз негізгі(Жол[] дәлелдер) {        // Стратегияларды дайындаңыз        BillingStrategy қалыпты стратегия    = BillingStrategy.қалыпты стратегия();        BillingStrategy happyHourStrategy = BillingStrategy.happyHourStrategy();        Клиенттік шот бірінші тұтынушы = жаңа Клиенттік шот(қалыпты стратегия);        // Қалыпты есеп айырысу        бірінші тұтынушы.қосу(100, 1);        // Бақытты сағатты бастаңыз        бірінші тұтынушы.setStrategy(happyHourStrategy);        бірінші тұтынушы.қосу(100, 2);        // Жаңа тұтынушы        Клиенттік шот екінші тұтынушы = жаңа Клиенттік шот(happyHourStrategy);        екінші тұтынушы.қосу(80, 1);        // Тапсырыс беруші төлейді        бірінші тұтынушы.басып шығару();        // Бақытты сағатты аяқтаңыз        екінші тұтынушы.setStrategy(қалыпты стратегия);        екінші тұтынушы.қосу(130, 2);        екінші тұтынушы.қосу(250, 1);        екінші тұтынушы.басып шығару();    }}

Стратегия және ашық / жабық принцип

Жылдамдату және тежегіш мінез-құлық әрбір жаңаға жария етілуі керек автомобиль моделі.

Стратегия үлгісіне сәйкес сыныптың мінез-құлқы мұрагерлікпен берілмеуі керек. Керісінше, оларды интерфейстер көмегімен инкапсуляциялау керек. Бұл сәйкес келеді ашық / жабық принцип (OCP), ол сыныптарды кеңейту үшін ашық, бірақ өзгерту үшін жабық деп ұсынады.

Мысал ретінде автомобиль класын қарастырайық. Автокөліктің екі мүмкін функционалдығы тежегіш және тездету. Модельдер арасында жылдамдық пен тежегіштің әрекеттері жиі өзгеретіндіктен, жалпы тәсіл бұл әрекеттерді ішкі сыныптарға енгізу болып табылады. Бұл тәсілдің елеулі кемшіліктері бар: жылдамдықтың жоғарылауы және тежегіштің әрекеті автомобильдің әр жаңа моделінде жариялануы керек. Бұл мінез-құлықты басқару жұмысы модельдер саны көбейген сайын айтарлықтай артады және кодтардың модельдер бойынша қайталануын талап етеді. Сонымен қатар, әрқайсысында кодты зерттемей, әр модель үшін нақты мінез-құлықты анықтау оңай емес.

Стратегия үлгісі қолданылады мұрагерліктің орнына композиция. Стратегия үлгісінде мінез-құлық жеке интерфейстер және осы интерфейстерді жүзеге асыратын нақты кластар ретінде анықталады. Бұл мінез-құлық пен мінез-құлықты пайдаланатын сынып арасындағы айырмашылықты жақсартуға мүмкіндік береді. Мінез-құлықты оны қолданатын сыныптарды бұзбай-ақ өзгертуге болады, ал сыныптар ешқандай маңызды кодтық өзгерістерді қажет етпей қолданылған нақты іске асыруды өзгерту арқылы мінез-құлық арасында ауыса алады. Мінез-құлықтарды жұмыс кезінде де, дизайн кезінде де өзгертуге болады. Мысалы, автомобиль объектісінің тежегіш әрекетін келесіден өзгертуге болады BrakeWithABS () дейін Тежегіш () өзгерту арқылы тежегіш мүше:

тежегіш = жаңа Тежегіш();
/ * Инкапсуляцияланған алгоритмдер отбасы * Интерфейс және оның орындалуы */қоғамдық интерфейс IBrakeТәртіп {    қоғамдық жарамсыз тежегіш();}қоғамдық сынып BrakeWithABS құрал-саймандар IBrakeТәртіп {    қоғамдық жарамсыз тежегіш() {        Жүйе.шығу.println(«ABS бар тежегіш»);    }}қоғамдық сынып Тежегіш құрал-саймандар IBrakeТәртіп {    қоғамдық жарамсыз тежегіш() {        Жүйе.шығу.println(«Қарапайым тежегіш басылды»);    }}/ * Жоғарыда келтірілген алгоритмдерді алмастыра алатын клиент * /қоғамдық реферат сынып Автокөлік {    жеке IBrakeТәртіп тежегіш;    қоғамдық Автокөлік(IBrakeТәртіп тежегіш) {      бұл.тежегіш = тежегіш;    }    қоғамдық жарамсыз Тежеу() {        тежегіш.тежегіш();    }    қоғамдық жарамсыз setBrakeBehavior(IBrakeТәртіп brakeType) {        бұл.тежегіш = brakeType;    }}/ * 1-клиент конструкторда бір алгоритмді қолданады (Тежегіш) * /қоғамдық сынып Седан ұзарады Автокөлік {    қоғамдық Седан() {        тамаша(жаңа Тежегіш());    }}/ * 2-клиент конструкторда басқа алгоритмді қолданады (BrakeWithABS) * /қоғамдық сынып Жол талғамайтын көлік ұзарады Автокөлік {    қоғамдық Жол талғамайтын көлік() {        тамаша(жаңа BrakeWithABS());    }}/ * Автомобиль мысалын қолдану * /қоғамдық сынып CarErmal {    қоғамдық статикалық жарамсыз негізгі(ақтық Жол[] дәлелдер) {        Автокөлік седан = жаңа Седан();        седан.Тежеу();  // Бұл «тежегіш» класын шақырады        Автокөлік су көлігі = жаңа Жол талғамайтын көлік();        су көлігі.Тежеу();    // Бұл «BrakeWithABS» класын шақырады        // тежегіштің жұмысын динамикалық түрде орнатыңыз        су көлігі.setBrakeBehavior( жаңа Тежегіш() );        су көлігі.Тежеу();    // Бұл «тежегіш» класын шақырады    }}

Сондай-ақ қараңыз

Әдебиеттер тізімі

  1. ^ «Стратегияны құру үлгісі - проблема, шешім және қолдану». w3sDesign.com. Алынған 2017-08-12.
  2. ^ Эрик Фриман, Элизабет Фриман, Кэти Сьерра және Берт Бейтс, Бірінші дизайн өрнектерін басқарыңыз, Бірінші басылым, 1 тарау, 24 бет, O'Reilly Media, Inc, 2004 ж. ISBN  978-0-596-00712-6
  3. ^ Эрих Гамма, Ричард Хельм, Ральф Джонсон, Джон Влиссидес (1994). Дизайн үлгілері: объектіге бағытталған бағдарламалық жасақтаманың қайта пайдаланылатын элементтері. Аддисон Уэсли. бет.315ff. ISBN  0-201-63361-2.CS1 maint: бірнеше есімдер: авторлар тізімі (сілтеме)
  4. ^ «Стратегияны құру үлгісі - құрылым және ынтымақтастық». w3sDesign.com. Алынған 2017-08-12.
  5. ^ http://www.mcdonaldland.info/2007/11/28/40/

Сыртқы сілтемелер