設計模式(一)之策略模式


  • 關於設計模式的總結有結合網上優質的文章以及本人在實際工作當中使用到的場景概述。
  • 會總結關於工作當中我們做為開發者常用到的幾種設計模式。
  • 由於工作原因,關於博文的總結都是在工作之余完成的,有不好的地方歡迎指正,謝謝。
  • 所有關於設計模式的代碼,都會托管到:設計模式代碼,歡迎關注。

時空鏈接:

  1. 設計模式(一)之策略模式
  2. 設計模式(二)之責任鏈模式
  3. 設計模式(三)之模板模式
  4. 設計模式(四)之裝飾者模式
  5. 設計模式(五)之適配器模式

在日常工作開發中我們為什么要使用到設計模式呢?本人做為一名JAVA開發人員,最先想到的是"萬物皆對象",不服咱就new一個唄。但是為了開發人員之間的通信,為了可以更准確地描述及問題的解決方案,又不得不考慮到設計模式。好處呢?當然是提高代碼的復用性、擴展性和減少代碼冗余的問題了。可以使同開發者更好的閱讀和理解代碼邏輯。

設計模式六大原則

  • 開閉原則(Open Close Principle)

開閉原則就是說對擴展開放,對修改關閉。在程序需要進行拓展的時候,不能去修改原有的代碼,實現一個熱插拔的效果。所以一句話概括就是:為了程序的擴展性好,易於維護和升級。

  • 里氏代換原則(Liskov Substitution Principle)

(來自百度百科)里氏代換原則(Liskov Substitution Principle)面向對象設計的基本原則之一。里氏代換原則中說,任何基類可以出現的地方,子類一定可以出現。LSP是繼承復用的基石,只有當衍生類可以替換掉基類,軟件單位的功能不受到影響時,基類才能真正被復用,而衍生類也能夠在基類的基礎上增加新的行為。里氏代換原則是對"開-閉"原則的補充。實現"開-閉"原則的關鍵步驟就是抽象化。而基類與子類的繼承關系就是抽象化的具體實現。所以里氏代換原則是對實現抽象化的具體步驟的規范。

  • 依賴倒轉原則(Dependence Lnversion Principle)

這個是開閉原則的基礎。具體內容:針對接口編程,依賴於抽象而不依賴於具體。(也就是說,接口或抽象類不依賴於實現類,實現類依賴於接口或者抽象類。更精簡的定義就是:面向接口編程(Object-Oriented Design,OOD))。

  • 接口隔離原則(Interface Segregation Principle)

使用多個隔離的接口,比使用單個接口好。還是一個降低類之間耦合度為基准。都是為了服務"降低依賴,降低耦合"。

  • 迪米特法則(Demeter Principle)

(來自百度百科)迪米特法則又叫做最少知識原則(Least Knowledge Principle 簡寫LKP),一個實體應當盡量少的與其它實體之間發生相互作用,使得系統功能模塊相對獨立。也就是說一個類對於其他類知道的越少越好,一個對象應對其他對象有盡可能少的了解,只和朋友通信,不和陌生人說話。

  • 合成復用原則(Composite Reuse Principle)

合成復用原則是盡量使用合成/聚合的方式,而不是使用繼承(表示在軟件復用時,要盡量先使用組合或聚合等關聯關系來實現,其次才考慮使用繼承關系來實現)。

設計模式分類

設計模式總體來說分為三大類

  1. 創建型模式:原型模式、單例模式、工廠方法模式、抽象工廠模式、建造者模式共五種。
  2. 結構型模式:適配器模式、裝飾模式、代理模式、外觀模式、橋接模式、組合模式、享元模式共七種。
  3. 行為模式:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式共十一種。

下面開始我們的策略模式吧

策略模式

  • 什么是策略模式?
  1. 其實策略模式就是對算法的包裝,是把算法的責任和算法本身分割開來,委派給不同的對象管理,最終實現解決多重if判斷問題。舉個例子,比如我們平時出行旅行吧,可能每個人對於選擇的交通出行方式各不相同,有騎自行車、有坐火車、有坐高鐵,也有乘坐飛機的。雖然出行方式各不相同,但做的事情都大致相同-去旅行。
  2. 上面的場景也可以這樣描述:如果在一個系統中有許多類,它們之間的區別僅在於它們的行為,那么使用策略模式可以動態地讓一個對象在許多行為中選擇一種行為(也就是上面所說解決了多重if判斷問題)。
  • 使用場景
  1. 相信很多開發者或多或少都接觸過erp系統開發,在進行流程審核時,可以選擇不同的類型來達到最終的審核結果。比如有工作匯報、KPI/OKR、微創新等審核流程。
  2. 說說我們平時的聚合支付吧,有支付寶支付、小米支付、京東支付和微信支付等等,大大小小的平台,這時作為開發者的我們要對接那么多的平台,要寫那么多的if else if ,想想就難受,還是使用策略模式來解決該問題吧。
public String audit(String type){
	if(type.equals("工作匯報")) {
		//TODO
		return "工作匯報流程審核處理";
	}
	if(type.equals("KPI/OKR")) {
		//TODO
		return "KPI/OKR流程審核處理";
	}
	if(type.equals("微創新")) {
		//TODO
		return "微創新流程審核處理";
	}
	return "未找到審核處理流程";
}

來自網絡圖對策略模式的圖解:

  • 策略模式環境搭建
    創建項目,名稱為:springboot_design_pattern
  1. maven環境依賴
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>
	
	 <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
	  <version>2.6</version>
    </dependency>

    <!--  配置文件顯示-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>2.3.1</version>
          <configuration>
            <source>1.8</source>
            <target>1.8</target>
            <encoding>utf-8</encoding>
          </configuration>
        </plugin>
        <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
          <version>2.2.5.RELEASE</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>

定義一個抽象角色

package com.lee.strategy.service;

/**
 * @author zfl_a
 * @date 2020/8/10
 * @project springboot_design_pattern
 */
public abstract class AuditService {

    /**
     * 抽象,子類具體實現
     * @param name
     * @param msg
     * @return
     */
    public abstract boolean operation(String name,String msg);

    /**
     * 公用方法
     * @param typeName
     */
    protected void updateAuditInfo(String typeName){
        System.out.println("更新了"+typeName+"審核信息");
    }
}

具體實現-微創新實現類

package com.lee.strategy.service.impl;

import com.lee.strategy.service.AuditService;
import org.springframework.stereotype.Service;

/**
 * @author zfl_a
 * @date 2020/8/10
 * @project springboot_design_pattern
 */
@Service
public class InnovateAuditServiceImpl extends AuditService {
    @Override
    public boolean operation(String name, String msg) {

        //TODO
        System.out.println(name+"操作了微創新審核流程,留言內容:"+msg);

        //調用父類
        super.updateAuditInfo("微創新");
        return true;
    }
}

具體實現-KPI/OKR實現類

package com.lee.strategy.service.impl;

import com.lee.strategy.service.AuditService;
import org.springframework.stereotype.Service;

/**
 * @author zfl_a
 * @date 2020/8/10
 * @project springboot_design_pattern
 */
@Service
public class KPIAuditServiceImpl extends AuditService {
    @Override
    public boolean operation(String name, String msg) {

        //TODO
        System.out.println(name+"操作了KPI/OKR審核流程,留言內容:"+msg);

        //調用父類
        super.updateAuditInfo("KPI/OKR");
        return true;
    }
}

具體實現-工作匯報實現類

package com.lee.strategy.service.impl;

import com.lee.strategy.service.AuditService;
import org.springframework.stereotype.Service;

/**
 * @author zfl_a
 * @date 2020/8/10
 * @project springboot_design_pattern
 */
@Service
public class WorkReportAuditServiceImpl extends AuditService {
    @Override
    public boolean operation(String name, String msg) {

        //TODO
        System.out.println(name+"操作了工作匯報審核流程,留言內容:"+msg);

        //調用父類
        super.updateAuditInfo("工作匯報");
        return true;
    }
}

定義一個枚舉類,封裝三個實現類對應的信息,相當於上下文。(可在數據庫中實現)

package com.lee.strategy.enumeration;

/**
 * @author zfl_a
 * @Desc 定義了枚舉類實現,也可以定義在數據庫中,根據類型取值
 * @date 2020/8/10
 * @project springboot_design_pattern
 */
public enum AuditEnum {

    INNOVATE_ADUIT("2","innovateAuditServiceImpl"),
    KPI_AUDIT("3","KPIAuditServiceImpl"),
    WORK_REPORT_AUDIT("4","workReportAuditServiceImpl");

    private String type;
    private String impl;

    private AuditEnum(String type,String impl){
        this.type = type;
        this.impl = impl;
    }

    public static String getImpl(String type){
        for(AuditEnum auditEnum : AuditEnum.values()) {
            if(type.equals(auditEnum.getType())) {
                return auditEnum.getImpl();
            }
        }
        return null ;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getImpl() {
        return impl;
    }

    public void setImpl(String impl) {
        this.impl = impl;
    }
}

定義一個具體業務接口

package com.lee.strategy.service;

/**
 * @author zfl_a
 * @date 2020/8/10
 * @project springboot_design_pattern
 */
public interface StrategyService {

    boolean audit(String name,String msg,String type);
}

定義一個具體業務接口實現類

package com.lee.strategy.service.impl;

import com.lee.strategy.enumeration.AuditEnum;
import com.lee.strategy.service.AuditService;
import com.lee.strategy.service.StrategyService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;

/**
 * @author zfl_a
 * @date 2020/8/10
 * @project springboot_design_pattern
 */
@Service
public class StrategyServiceImpl implements StrategyService {

    //自動裝配AuditService的所有實現類,以全類名首字母小寫作為key
    @Autowired
    private Map<String, AuditService> auditMap ;

    @Override
    public boolean audit(String name, String msg, String type) {

        if(StringUtils.isBlank(type)) {
            return false ;
        }

        //根據不同類型審核
        String auditType = AuditEnum.getImpl(type);
        if(StringUtils.isNotBlank(auditType)) {
            AuditService auditService = auditMap.get(auditType);
            auditService.operation(name,msg);
        }

        return true;
    }
}

定義一個策略Controller

package com.lee.strategy.controller;

import com.lee.strategy.service.StrategyService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * @author zfl_a
 * @date 2020/8/10
 * @project springboot_design_pattern
 */
@RestController
@RequestMapping("/strategy")
public class StrategyController {

    @Autowired
    private StrategyService strategyService ;

    /**
     * 審核流程 返回值不建議Map,可定義成響應結果對象封裝
     * @param name 審核人
     * @param msg 留言內容
     * @param type 類型 2微創新 3KPI/OKR 4工作匯報,在實際工作當中根據實際業務
     * @return
     */
    @PostMapping("/audit")
    public Map<String,Object> audit(String name,String msg ,String type) {

        Map<String,Object> results = new HashMap<>();
        results.put("code","200");
        results.put("msg","審核成功");

        if(StringUtils.isBlank(type)) {
            results.put("code","-1");
            results.put("msg","請傳遞審核類型");
            return results ;
        }

        boolean audit = strategyService.audit(name, msg, type);
        if(!audit) {
            results.put("code","-2");
            results.put("msg","審核失敗");
        }
        return results ;
    }
}

訪問,如下圖所示:

最終結果:

所有關於設計模式的代碼,都會托管到:設計模式代碼,歡迎關注。希望和大家一起共同成長!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM