マップと関数型インターフェイスのメソッド、if-else のエレガントなソリューション

ビジネス シナリオがあります。クーポンのタイプresourceTypeとコードに従ってresourceId、grantType とコレクション ルールをクエリします。

実現方法:

  1. クーポンタイプに従って resourceType -> どのデータテーブルをクエリするかを決定します

  2. コードに従って resourceId -> 対応するデータテーブルに移動して、クーポン配布方法のgrantTypeと収集ルールをクエリします。

クーポンにはさまざまな種類があり、さまざまなデータベース テーブルに対応しています。

  • 赤い封筒—赤い封筒の発行ルール

  • ショッピングクーポン - ショッピングクーポンフォーム

  • QQメンバー

  • テイクアウト会員

実際のクーポンはこれらよりもはるかに多く、この要件にはビジネス割り当てのロジックを記述する必要があります。

最初に思い浮かぶのは、if-else または switch case です。

switch(resourceType){
 case "红包": 
  查询红包的派发方式 
  break;
 case "购物券": 
  查询购物券的派发方式
  break;
 case "QQ会员" :
  break;
 case "外卖会员" :
  break;
 ......
 default : logger.info("查找不到该优惠券类型resourceType以及对应的派发方式");
  break;
}

このように書こうとすると、メソッドのコードが長すぎて可読性に影響します。(上記の例を一文だけで見ないでください。実際には多くの行があります)

また、if-elseコード全体の行数が多いため修正が難しく、保守性が低いです。

戦略パターン

ストラテジモードはif文内のロジックを抽出してクラスとして記述するモードで、特定のロジックを変更したい場合は、特定の実装クラスのロジックを変更するだけで済み、保守性が向上します。

ビジネス ロジックがディスパッチされるとき、戦略モードは依然として if-else です が、最初の if-else アイデアよりも維持する方が優れています。

switch(resourceType){
 case "红包": 
  String grantType=new Context(new RedPaper()).ContextInterface();
  break;
 case "购物券": 
  String grantType=new Context(new Shopping()).ContextInterface();
  break;
 
 ......
 default : logger.info("查找不到该优惠券类型resourceType以及对应的派发方式");
  break;

しかし、欠点も明らかです。

  • if-else 判定が多ければ、それに対応する特定戦略実装クラスも多数存在します。特定戦略実装クラスは上記の 2 つだけです。クエリ赤封筒配布メソッドは RedPaper クラスに記述され、お買い物クーポンはクラス RedPaper に記述されます。別のクラス Shopping Inside。リソース タイプには複数の QQ メンバーとテイクアウト メンバーがあるため、さらに 2 つのカテゴリを記述する必要はありませんか? ちょっとしたトラブル

  • 派遣全体のビジネスロジックを見逃すことはできない

Map+ 機能インターフェイス

Java8ラムダ式の新機能を利用する

  • 判定条件をキーに入れる

  • 対応するビジネス ロジックが value に配置されます

このように書くメリットは非常に直感的であり、判定条件に対応するビジネスロジックを直接確認できることです。

要件: クーポン (リソース) タイプresourceType およびコード化された resourceIdに従って 、配布メソッドGrantType をクエリします。

上記のコード:

@Service
public class QueryGrantTypeService {
 
    @Autowired
    private GrantTypeSerive grantTypeSerive;
    private Map<String, Function<String,String>> grantTypeMap=new HashMap<>();

    /**
     *  初始化业务分派逻辑,代替了if-else部分
     *  key: 优惠券类型
     *  value: lambda表达式,最终会获得该优惠券的发放方式
     */
    @PostConstruct
    public void dispatcherInit(){
        grantTypeMap.put("红包",resourceId->grantTypeSerive.redPaper(resourceId));
        grantTypeMap.put("购物券",resourceId->grantTypeSerive.shopping(resourceId));
        grantTypeMap.put("qq会员",resourceId->grantTypeSerive.QQVip(resourceId));
    }
 
    public String getResult(String resourceType){
        //Controller根据 优惠券类型resourceType、编码resourceId 去查询 发放方式grantType
        Function<String,String> result=getGrantTypeMap.get(resourceType);
        if(result!=null){
         //传入resourceId 执行这段表达式获得String型的grantType
            return result.apply(resourceId);
        }
        return "查询不到该优惠券的发放方式";
    }
}

単一の if ステートメント ブロックにビジネス ロジックの行が多数ある場合、これらのビジネス オペレーションを抽出して、別個のサービスとして記述することができます。

//具体的逻辑操作

@Service
public class GrantTypeSerive {

    public String redPaper(String resourceId){
        //红包的发放方式
        return "每周末9点发放";
    }
    public String shopping(String resourceId){
        //购物券的发放方式
        return "每周三9点发放";
    }
    public String QQVip(String resourceId){
        //qq会员的发放方式
        return "每周一0点开始秒杀";
    }
}

入力パラメータは String resourceIdデータベースをチェックするために使用されますが、ここでは簡略化されており、パラメータを渡した後は処理されません。

httpで呼び出した結果:

@RestController
public class GrantTypeController {

    @Autowired
    private QueryGrantTypeService queryGrantTypeService;

    @PostMapping("/grantType")
    public String test(String resourceName){
        return queryGrantTypeService.getResult(resourceName);
    }
}

Map+ 関数インターフェースの使用には次のような欠点もあります。

チームメイトはラムダ式を知っている必要があります。自分で Baidu に行かせることができない場合でも、学ぶべきことは学ばなければなりません。

おすすめ

転載: blog.csdn.net/baidu_38493460/article/details/130501351