项目作者: oscarludick

项目描述 :
The strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.
高级语言: TypeScript
项目地址: git://github.com/oscarludick/strategy-pttrn-ts.git
创建时间: 2020-12-30T17:16:46Z
项目社区:https://github.com/oscarludick/strategy-pttrn-ts

开源协议:

下载


Strategy Pattern

The following text was obtained from the book Head First Desing Patterns.

Design principles used in Stragegy pattern

  • Identify the aspects of your application that vary and separate them from what stays the same.
  • Program to an interface, not an implementation.
  • Favor composition over inheritance.

The strategy pattern

Take what varies and “encapsulate” it so it won’t affect the rest of your code. It will result on fewer unintended consequences from code changes and more flexibility in your systems. If you have got some aspect on your code that is changing, say with every new requierement, then you know you have got a behavior that needs to be pulled out and separated from all the stuff that doesn’t change.

One of the desing principles says “Program to an interface” but really means “Program to a supertype”, we can rephrase as “the declaration type of the variables should be a supertype, usually an abstract class or interface, so that the objects assigned to those variables can be of any concrate implementation of the supertype, wich means the class declaring them doesn´t have to know about the actual object types.”

Creating systems using composition gives you a lot more flexibility. Not only does it let you encapsulate a family of algorithms into their own set of classes, but it also lets you change behavior in runtime as long the object you are composing with implements the correct behavior interface.

In resume

Take the parts that vary and encapsulate them, so later you can alter or extend the parts that vary without affecting those that do not.

The strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.

The Hero/Villian NPC Example

Hero/Villian example

The HeroNPC extends from the abstract class CommonNPC.

  1. export class HeroNPC extends CommonNPC {
  2. attackBehavior: IAttackBehavior;
  3. defendBehavior: IDefenseBehavior;
  4. constructor(
  5. mAttackBehavior?: IAttackBehavior,
  6. mDefendBehavior?: IDefenseBehavior
  7. ) {
  8. super();
  9. this.attackBehavior = mAttackBehavior
  10. ? mAttackBehavior
  11. : new AttackWithSword();
  12. this.defendBehavior = mDefendBehavior
  13. ? mDefendBehavior
  14. : new DefenseWithShield();
  15. }
  16. whatIam(): void {
  17. console.log("I am a hero");
  18. }
  19. }

The CommonNPC is composing IAttackBehavior and IDefenseBehavior

  1. export abstract class CommonNPC {
  2. abstract attackBehavior: IAttackBehavior;
  3. abstract defendBehavior: IDefenseBehavior;
  4. constructor() {}
  5. abstract whatIam(): void;
  6. /**All NPC can talk */
  7. talk(message: string) {
  8. console.log(message);
  9. }
  10. performAttack() {
  11. this.attackBehavior.attack();
  12. }
  13. performDefense() {
  14. this.defendBehavior.defend();
  15. }
  16. }

Encapsulating the behaviors/algorithms

  1. export class AttackWithMagic implements IAttackBehavior {
  2. attack(): void {
  3. console.log("Attack with magic");
  4. }
  5. }

The result

  1. const hero: CommonNPC = new HeroNPC();
  2. hero.whatIam();
  3. hero.performAttack();
  4. hero.performDefense();
  5. const villian: CommonNPC = new VillianNPC();
  6. villian.whatIam();
  7. villian.performAttack();
  8. villian.performDefense();
  1. I am a hero
  2. Attack with sword
  3. Defend with shield
  4. I am a villian
  5. Attack with magic
  6. Defend with sword