Summary of strategy mode, applicable scenarios, advantages and disadvantages, code examples

Related reference blog posts:

Blog Garden:

1 Introduction

A series of algorithms are defined and encapsulated. They can be replaced with each other. The adjustment or addition of an algorithm will not affect other algorithms. The specific algorithm is selected during the execution. What algorithm is used is delayed until At runtime, the system is more flexible and reusable. This mode can reduce the number of if else, which is behavioral.

  • Context package role

Also called the context role, it plays a role of encapsulation, shielding high-level modules from direct access to strategies and algorithms, and encapsulating possible changes.

  • Strategy abstract strategy role

The abstraction of a strategy and algorithm family, usually an interface, defines the methods and attributes that each strategy or algorithm must have.

  • ConcreateStrategy

To implement operations in abstract strategies, this class has specific algorithms.

1.1 Expansion and reuse problems caused by inheritance

Inheritance as one of the three major elements of object-oriented (encapsulation, inheritance, polymorphism) why does it cause problems, how to solve the problem and then form a design pattern, the head frist design pattern book uses ducks as an example to explain under what circumstances inheritance Ways can cause problems. First of all, there are various ducks, so it is natural to think that various ducks inherit from a parent class: the parent class is Duck, the existing mallard ducks GreenHeadDuck and red head ducks RedHeadDuck:

public abstract Class Duck{
    
    
  public void quack(){
    
    }
  public void swin(){
    
    }
  public abstract void display();
}
publci class GreenHeadDuck:Duck{
    
    
    public overrid void  display(){
    
    
      //外观绿头
    }
}
publci class ReadHeadDuck:Duck{
    
    
    public overrid void  display(){
    
    
      //外观红头
    }
}

All ducks in the parent class can quack and swim, but their appearance is different. Therefore, display is an abstract method, which can be overridden by subclasses that inherit it. Now we need to add a new kind of duck, but this duck is a toy rubber duck, we follow the inheritance method, the rubber duck implementation code is as follows:

publci class RubberDuck:Duck{
    
    
   public override void qucak(){
    
    
    //覆盖成吱吱吱叫
  }
    public override void  display(){
    
    
      //外观是橡皮鸭
    }
}

Because the rubber duck will not call like other ducks, we need to rewrite the above code to cover the way the rubber duck calls. Now there is a requirement that we need to make the ducks fly. According to the inheritance method, we can add the fly method to the parent class Duck to make all the ducks fly. But the problem arises, the rubber duck can't fly, so we can override the fly method in RubberDuck just like the qucak method.

public abstract class Duck{
    
    
  public void quack(){
    
    }
  public void swin(){
    
    }
  public abstract void display();
    public void fly(){
    
    }
}
publci class RubberDuck:Duck{
    
    
  public override void qucak(){
    
    
    //覆盖成吱吱吱叫
  }
    public override void  display(){
    
    
      //外观是橡皮鸭
    }
    public override void fly(){
    
    
        //覆盖,什么都不做
    }
}

So far we have discovered the problems caused by inheritance:

  1. The code is repeated in multiple subcategories.
  2. It is difficult to know the behavior of all subclasses.
  3. The behavior of running subclasses is not easy to change.
  4. Changes will affect the whole body, causing undesired changes in other subtypes.

Whenever a new subclass appears, it is necessary to check whether the superclass method needs to be overridden. For example, add a wooden toy duck (DecoyDuck), then the wooden duck will not bark or fly. Do we need to cover the methods of barking and flying?

1.2 Further improvements, using interfaces

Since quack and fly may change, we abstract quack and fly into interfaces. Only ducks that can call and fly inherit the interface's own implementation methods as required.

Using interfaces can solve part of the problem (no need to rewrite unnecessary methods), but it will cause the code to be unable to reuse, because the interface does not have an implementation, we have to write fly and quack in each subclass. For example, you want to write "Cracking" in the red head and green head, and "Squeaking" in the rubber duck.

1.3 Further improvements, strategy mode

After the above analysis, two principles of design patterns can be derived:

  1. Encapsulate the changing parts so that other parts will not be affected.
  2. For interface programming, not for implementation.
    Through the first design principle, we can extract the parts that are easy to change: the duck's flying behavior (fly) and the quack behavior (quack). Through the second design principle, we know that we need to use interfaces to represent each behavior, such as FlyBehavior and QuackBehavior, and each implementation of the behavior will implement one of the interfaces. In this way, the duck class is not responsible for implementing FlyBehavior and QuackBehavior, but is specifically implemented by the behavior class, and will not be tied to the duck subclass.

And "programming for interfaces" means "programming for supertypes". It can be clearly stated that the variable declaration type should be a super class, which means that the behavior variables we declare in the Duck parent class are FlyBehavior and QuackBehavior. The key to "programming for interfaces" lies in the "polymorphism" which is one of the three elements of object-oriented "Because of polymorphism, we can execute the method of the implementation class or subclass when calling the superclass method. So we modify the Duck class we wrote before, delete Fly() and Quack(), add FlyBehavior and QuackBehavior variables, and use the other two methods PerFormFly() and PerFormQuack() to perform two actions.

public abstract Class Duck{
    
    
    protected FlyBehavior flyBehavior;
    protected QuackBehavior quackBehavior;
  public void swin(){
    
    }
  public abstract void display()public void PerFormFly(){
    
    
      flyBehavior.fly();
   }
  public void PerFormQuack(){
    
    
      quackBehavior.quack();
   }
}

Write related classes and test:

//封装飞行行为
    public interface FlyBehavior
    {
    
    
        public void fly();
    }
    public class FlyWithWings : FlyBehavior
    {
    
    
        public void fly()
        {
    
    
            Console.WriteLine("用翅膀飞");
        }
    }
    public class FlyNoWay : FlyBehavior
    {
    
    
        public void fly()
        {
    
    
            Console.WriteLine("不飞,什么也不做");
        }
    }
    //封装叫声行为
    public interface QuackBehavior
    {
    
    
       public void quack();
    }

    public class Quack : QuackBehavior
    {
    
    
        public void quack()
        {
    
    
            Console.WriteLine("呱呱叫");
        }
    }
    public class Squack : QuackBehavior
    {
    
    
        public void quack()
        {
    
    
            Console.WriteLine("吱吱叫");
        }
    }
    public class MuteQuack : QuackBehavior
    {
    
    
        public void quack()
        {
    
    
            Console.WriteLine("不会叫");
        }
    }
    /// <summary>
    /// 鸭子超类
    /// </summary>
    public abstract class Duck {
    
    
        protected FlyBehavior flyBehavior;
        protected QuackBehavior quackBehavior;
        public void swin() {
    
     }
        public abstract void display();
        public void PerFormFly()
        {
    
    
            flyBehavior.fly();
        }
        public void PerFormQuack()
        {
    
    
            quackBehavior.quack();
        }
    }
    /// <summary>
    /// 绿头鸭
    /// </summary>
    public class GreenHeadDuck : Duck
    {
    
    
        public GreenHeadDuck() {
    
    
            flyBehavior = new FlyWithWings();
            quackBehavior = new Quack();
        }
        public override void display()
        {
    
    
            Console.WriteLine("绿头鸭,我的头顶有一片草原(*^_^*)");
        }
    }
    /// <summary>
    /// 橡皮鸭
    /// </summary>
    public class RubberDuck : Duck
    {
    
    
        public RubberDuck()
        {
    
    
            flyBehavior = new FlyNoWay();
            quackBehavior = new Squack();
        }
        public override void display()
        {
    
    
            Console.WriteLine("橡皮鸭");
        }
    }
        static void Main(string[] args)
        {
    
    
            //绿头鸭
            Duck greenHeadDuck = new GreenHeadDuck();
            greenHeadDuck.display();
            greenHeadDuck.PerFormQuack();
            greenHeadDuck.PerFormFly();
            Console.WriteLine("--------------------------");
            //橡皮鸭
            Duck rubberDuck = new RubberDuck();
            rubberDuck.display();
            rubberDuck.PerFormQuack();
            rubberDuck.PerFormFly();
            Console.ReadKey();
        }

As in the above test, we instantiated the behavior class through the construction method in the duck subclass, but established a bunch of dynamic functions that are not used. Can the behavior be dynamically set instead of instantiated in the constructor. So we can also add two methods of setting behavior SetFlyBehavior and SetQuackBehavior to test the dynamic setting behavior again.

/// <summary>
/// 鸭子超类
/// </summary>
public abstract class Duck {
    
    
    protected FlyBehavior flyBehavior;
    protected QuackBehavior quackBehavior;
    public void swin() {
    
     }
    public abstract void display();
    public void SetFlyBehavior(FlyBehavior flyBehavior) {
    
    
        this.flyBehavior = flyBehavior;
    }
    public void SetQuackBehavior(QuackBehavior quackBehavior) {
    
    
        this.quackBehavior = quackBehavior;
    }
    public void PerFormFly()
    {
    
    
        flyBehavior.fly();
    }
    public void PerFormQuack()
    {
    
    
        quackBehavior.quack();
    }
}

2. Applicable scenarios

  1. There are many types of systems, but their only difference is their behavior
  2. A system needs to dynamically choose one of several algorithms
  3. Multiple classes only have slightly different algorithms or behaviors
  4. Scenes where the algorithm needs to switch freely
  5. Scenarios that need to block algorithm rules

Precautions:

  • If the number of specific strategies exceeds 4, it is necessary to consider using a mixed mode.

3. Advantages

1. It can reduce ifelse sentences
2. Improve the confidentiality and security of the algorithm
3. Comply with the principle of opening and closing

4. Disadvantages

1. The client needs to know all the strategy classes and decide which strategy class to use by itself.
2. The number of classes increases

5. Code example

[External link image transfer failed, the source site may have an anti-leech link mechanism, it is recommended to save the image and upload it directly (img-bHcVnhWC-1608389668751)(https://img.hacpai.com/file/2019/07/image-447d0de5 .png?imageView2/2/w/768/format/jpg/interlace/1/q/100)]

Order strategy interface

public interface OrderStrategy {
    
    
    OrderTypeEnum supportType();
    void saveOrder();
}

Alipay ordering strategy

public class AlipayStrategy implements OrderStrategy {
    
    
    public OrderTypeEnum supportType() {
    
    
        return OrderTypeEnum.ALIPAY;
    }
    public void saveOrder() {
    
    
        System.out.println("支付宝支付完成");
    }
}

WeChat order strategy

public class WxpayStrategy implements OrderStrategy{
    
    
    public OrderTypeEnum supportType() {
    
    
        return OrderTypeEnum.WXPAY;
    }
    public void saveOrder() {
    
    
        System.out.println("微信支付完成");
    }
}

Empty strategy

public class EmptyStrategy implements OrderStrategy {
    
    
    public OrderTypeEnum supportType() {
    
    
        return null;
    }
    public void saveOrder() {
    
    
        System.out.println("没有支付方式");
    }
}

Order type enumeration class

public enum OrderTypeEnum {
    
    
    /**
     * 支付宝、微信
     */
    ALIPAY,WXPAY
}

Order factory class

public class OrderFactory {
    
    
    private OrderFactory(){
    
    
    }
    /** spring下通过spring来获取所有的bean */
    private static OrderStrategy[] strategies = new OrderStrategy[]{
    
    new AlipayStrategy(),new WxpayStrategy()};
    private static OrderStrategy EMPTY_STRATEGY = new EmptyStrategy();
    private static OrderStrategy getOrderStrategy(String orderType) {
    
    
        for (OrderStrategy handler : strategies) {
    
    
            if (handler.supportType().name().equals(orderType)) {
    
    
                return handler;
            }
        }
        return EMPTY_STRATEGY;
    }
    public static void saveOrder(String orderType){
    
    
        getOrderStrategy(orderType).saveOrder();
    }
}

Test class

public class StrategyTest {
    
    
    public static void main(String[] args) {
    
    
        OrderFactory.saveOrder("ALIPAY");
        OrderFactory.saveOrder("WXPAY");
        OrderFactory.saveOrder("ICBC");
    }
}

The output is:

支付宝支付完成
微信支付完成
没有支付方式

6. Source code analysis

6.1 Application in spring

Resource
[External link image transfer failed. The source site may have an anti-leech link mechanism. It is recommended to save the image and upload it directly (img-W5uzzXJg-1608389668755)(https://img.hacpai.com/file/2019/07/image- cd73df82.png?imageView2/2/w/768/format/jpg/interlace/1/q/100)]

As shown in the figure, there are different types of strategies.
[External link image transfer failed. The origin site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-lNPd49Zr-1608389668756)(https://img.hacpai.com/ file/2019/07/image-2ec69237.png?imageView2/2/w/768/format/jpg/interlace/1/q/100)]

InstantiationStrategy can tell from the name that it is a strategy mode.
[External link image transfer failed. The source site may have an anti-leech mechanism. It is recommended to save the image and upload it directly (img-kfYog01n-1608389668758)(https://img.hacpai) .com/file/2019/07/image-66f96b08.png?imageView2/2/w/768/format/jpg/interlace/1/q/100)]

[External link image transfer failed. The origin site may have an anti-leech link mechanism. It is recommended to save the image and upload it directly (img-00o1uMWV-1608389668759)(https://img.hacpai.com/file/2019/07/image-57873357) .png?imageView2/2/w/768/format/jpg/interlace/1/q/100)]

It can also be configured through the set method.

public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
    
    
   this.instantiationStrategy = instantiationStrategy;
}

7. Summary of strategy mode, class diagram

Strategy mode: defines the algorithm clusters and encapsulates them separately so that they can be replaced with each other. This mode makes the algorithm changes independent of the customers who use the algorithm

Guess you like

Origin blog.csdn.net/An1090239782/article/details/111411819