場合は、他の代わりに使用するデザインパターン

場合は、他の代わりに使用するデザインパターン

序文

物流業界は、典型的には(状態は、サードパーティシステムにおけるデータストリームを識別する関連付けられた後続の領収書を受け取り、各EDIは、パケットを送信する、EDIメッセージ(XMLフォーマット)を受信および送信を受信したことを含みます)。いくつかのタイプは、本明細書に領収書を列挙:MT1101、MT2101、MT4101、MT8104、MT8105、MT9999システムは、様々な確認応答パケットを受信した後に、ビジネスロジックに対応する処理を行います。もちろん、ここでとても一般的な実際のビジネス・シナリオではなく、プレゼンテーションの場合の受信処理

  • 領収書のクラスをシミュレート
@Data
public class Receipt {

    /**
     * 回执信息
     */
    String message;

    /**
     * 回执类型(`MT1101、MT2101、MT4101、MT8104、MT8105、MT9999`)
     */
    String type;

}
  • 領収書ジェネレータのシミュレーション
public class ReceiptBuilder {

    public static List<Receipt> generateReceiptList(){
        //直接模拟一堆回执对象
        List<Receipt> receiptList = new ArrayList<>();
        receiptList.add(new Receipt("我是MT2101回执喔","MT2101"));
        receiptList.add(new Receipt("我是MT1101回执喔","MT1101"));
        receiptList.add(new Receipt("我是MT8104回执喔","MT8104"));
        receiptList.add(new Receipt("我是MT9999回执喔","MT9999"));
        //......    
        return receiptList;
    }
}


伝統的な慣行-if-ELSEブランチ

List<Receipt> receiptList = ReceiptBuilder.generateReceiptList();
//循环处理
for (Receipt receipt : receiptList) {
    if (StringUtils.equals("MT2101",receipt.getType())) {
        System.out.println("接收到MT2101回执");
        System.out.println("解析回执内容");
        System.out.println("执行业务逻辑");
    } else if (StringUtils.equals("MT1101",receipt.getType())) {
        System.out.println("接收到MT1101回执");
        System.out.println("解析回执内容");
        System.out.println("执行业务逻辑");
    } else if (StringUtils.equals("MT8104",receipt.getType())) {
        System.out.println("接收到MT8104回执");
        System.out.println("解析回执内容");
        System.out.println("执行业务逻辑");
    } else if (StringUtils.equals("MT9999",receipt.getType())) {
        System.out.println("接收到MT9999回执");
        System.out.println("解析回执内容");
        System.out.println("执行业务逻辑");
        System.out.println("推送邮件");
    }
    // ......未来可能还有好多个else if
}

より複雑なのif-else分岐ビジネスロジックの顔で、私たちはに慣れている方法引き出すまたはオブジェクトとしてパッケージ構造があまりにも肥大化見ていないならば、他に呼び出すので、全体を。上記の例では、時に他のレシートが上昇し、の種類は分岐が、それぞれの追加レシートタイプより多くなる場合、あなたは、もし、他のブランチを変更または追加する必要があり、開口部の原則に違反してとするために、拡張子にオープン(クローズ)に近い修正


戦略モード+地図辞書

私たちは、その顧客との独立した変化の使用は独立しているアルゴリズムは、クライアントのみポリシー・インターフェースに依存しているように、私たちは、お互いを置き換えることができ、戦略パターンの目的は、一連のアルゴリズムをカプセル化することであることを知って、彼らは共通しています。上記のシナリオでは、クライアントはまだ方針の選択のためのいくつかのif-elseロジックを記述する必要があることを、我々は様々な戦略を抽出するために、ビジネスロジックの場合、他の支店を置くことができますが、それは避けられない、我々は工場出荷時に、このロジックを抽出することができますどこへ行くのクラスは、これは戦略パターン+シンプル工場、次のように、コードがあります

  • ポリシーのインターフェイス
/**
 * @Description: 回执处理策略接口
 * @Auther: wuzhazha
 */
public interface IReceiptHandleStrategy {

    void handleReceipt(Receipt receipt);

}
  • 特定のハンドラであるポリシー・インターフェース・クラス、
public class Mt2101ReceiptHandleStrategy implements IReceiptHandleStrategy {

    @Override
    public void handleReceipt(Receipt receipt) {
        System.out.println("解析报文MT2101:" + receipt.getMessage());
    }

}

public class Mt1101ReceiptHandleStrategy implements IReceiptHandleStrategy {

    @Override
    public void handleReceipt(Receipt receipt) {
        System.out.println("解析报文MT1101:" + receipt.getMessage());
    }

}

public class Mt8104ReceiptHandleStrategy implements IReceiptHandleStrategy {

    @Override
    public void handleReceipt(Receipt receipt) {
        System.out.println("解析报文MT8104:" + receipt.getMessage());
    }

}

public class Mt9999ReceiptHandleStrategy implements IReceiptHandleStrategy {

    @Override
    public void handleReceipt(Receipt receipt) {
        System.out.println("解析报文MT9999:" + receipt.getMessage());
    }

}
  • ポリシーコンテキストクラス(ポリシーホルダーインタフェース)
/**
 * @Description: 上下文类,持有策略接口
 * @Auther: wuzhazha
 */
public class ReceiptStrategyContext {

    private IReceiptHandleStrategy receiptHandleStrategy;

    /**
     * 设置策略接口
     * @param receiptHandleStrategy
     */
    public void setReceiptHandleStrategy(IReceiptHandleStrategy receiptHandleStrategy) {
        this.receiptHandleStrategy = receiptHandleStrategy;
    }

    public void handleReceipt(Receipt receipt){
        if (receiptHandleStrategy != null) {
            receiptHandleStrategy.handleReceipt(receipt);   
        }
    }
}
  • 戦略工場
/**
 * @Description: 策略工厂
 * @Auther: wuzhazha
 */
public class ReceiptHandleStrategyFactory {

    private ReceiptHandleStrategyFactory(){}

    public static IReceiptHandleStrategy getReceiptHandleStrategy(String receiptType){
        IReceiptHandleStrategy receiptHandleStrategy = null;
        if (StringUtils.equals("MT2101",receiptType)) {
            receiptHandleStrategy = new Mt2101ReceiptHandleStrategy();
        } else if (StringUtils.equals("MT8104",receiptType)) {
            receiptHandleStrategy = new Mt8104ReceiptHandleStrategy();
        }
        return receiptHandleStrategy;
    }
}
  • クライアント
public class Client {

    public static void main(String[] args) {
        //模拟回执
        List<Receipt> receiptList = ReceiptBuilder.generateReceiptList();
        //策略上下文
        ReceiptStrategyContext receiptStrategyContext = new ReceiptStrategyContext();
        for (Receipt receipt : receiptList) {
            //获取并设置策略
            IReceiptHandleStrategy receiptHandleStrategy = ReceiptHandleStrategyFactory.getReceiptHandleStrategy(receipt.getType());
            receiptStrategyContext.setReceiptHandleStrategy(receiptHandleStrategy);
            //执行策略
            receiptStrategyContext.handleReceipt(receipt);
        }
    }
}

メッセージMT2101を解析します:私はああ、MT2101のレシートメッセージだ
私はMT8104のレシートメッセージああ午前:メッセージのMT8104を解析

私たちの目標は次の場合に、他の排除することですので、これが必要になりますReceiptHandleStrategyFactory私の戦略を保存するための辞書の方法を使用して、工場で政策改革をし、キーと値の構造を持つマップ、地図を使用することは良い選択です。次のように少し、修正の下で

/**
 * @Description: 策略工厂
 * @Auther: wuzhazha
 */
public class ReceiptHandleStrategyFactory {

    private static Map<String,IReceiptHandleStrategy> receiptHandleStrategyMap;

    private ReceiptHandleStrategyFactory(){
        this.receiptHandleStrategyMap = new HashMap<>();
        this.receiptHandleStrategyMap.put("MT2101",new Mt2101ReceiptHandleStrategy());
        this.receiptHandleStrategyMap.put("MT8104",new Mt8104ReceiptHandleStrategy());
    }

    public static IReceiptHandleStrategy getReceiptHandleStrategy(String receiptType){
        return receiptHandleStrategyMap.get(receiptType);
    }
}

場合は、他の戦略+シンプルなプラントソリューションのモードの形質転換後、私たちはいつでも新しい領収書、ちょうど新しい受信処理戦略を追加、および変更構造を排除しているReceiptHandleStrategyFactory地図のコレクションを。あなたは開閉の原則とプログラムの一貫性を保つためにしたい場合は、我々は調整する必要がありReceiptHandleStrategyFactory、取得モード処理戦略を反射の仕方によって、指定されたすべてのパッケージの下に入るIReceiptHandleStrategy実装クラスは、ディクショナリマップに入ります。


Chain of Responsibilityパターン

Chain of Responsibilityパターンは、オブジェクト行動パターンです。Chain of Responsibilityパターン、自宅でそれらの各オブジェクト参照の多くのオブジェクトにチェーンを形成するために一緒に接続されています。チェーン決意処理要求に特定のオブジェクトまで、この連鎖移動要求です。それは、クライアントの場合に責任の動的システムの再編成や分布に影響を与えることができないように、この要求クライアントが、最終的に要求を処理している鎖にオブジェクトを認識していない発行

  • 領収書の処理インタフェース
/**
 * @Description: 抽象回执处理者接口
 * @Auther: wuzhazha
 */
public interface IReceiptHandler {

    void handleReceipt(Receipt receipt,IReceiptHandleChain handleChain);

}
  • 責任のチェーンインタフェース
/**
 * @Description: 责任链接口
 * @Auther: wuzhazha
 */
public interface IReceiptHandleChain {

    void handleReceipt(Receipt receipt);
}
  • 責任のチェーンインタフェースの実装クラス
/**
 * @Description: 责任链实现类
 * @Auther: wuzhazha
 */
public class ReceiptHandleChain implements IReceiptHandleChain {
    //记录当前处理者位置
    private int index = 0;
    //处理者集合
    private static List<IReceiptHandler> receiptHandlerList;

    static {
        //从容器中获取处理器对象
        receiptHandlerList = ReceiptHandlerContainer.getReceiptHandlerList();
    }

    @Override
    public void handleReceipt(Receipt receipt) {
        if (receiptHandlerList !=null && receiptHandlerList.size() > 0) {
            if (index != receiptHandlerList.size()) {
                IReceiptHandler receiptHandler = receiptHandlerList.get(index++);
                receiptHandler.handleReceipt(receipt,this);
            }
        }
    }
}
  • 特定のレシートハンドラ
public class Mt2101ReceiptHandler implements IReceiptHandler {

    @Override
    public void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain) {
        if (StringUtils.equals("MT2101",receipt.getType())) {
            System.out.println("解析报文MT2101:" + receipt.getMessage());
        } 
        //处理不了该回执就往下传递
        else {          
            handleChain.handleReceipt(receipt);
        }
    }
}

public class Mt8104ReceiptHandler implements IReceiptHandler {

    @Override
    public void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain) {
        if (StringUtils.equals("MT8104",receipt.getType())) {
            System.out.println("解析报文MT8104:" + receipt.getMessage());
        }
        //处理不了该回执就往下传递
        else {
            handleChain.handleReceipt(receipt);
        }
    }
}
  • 容器を処理することによって責任の連鎖(ばね場合、取得したことにより、射出依存的であってもよいIReceiptHandlerサブクラスオブジェクト)
/**
 * @Description: 处理者容器
 * @Auther: wuzhazha
 */
public class ReceiptHandlerContainer {

    private ReceiptHandlerContainer(){}

    public static List<IReceiptHandler> getReceiptHandlerList(){
        List<IReceiptHandler> receiptHandlerList = new ArrayList<>();
        receiptHandlerList.add(new Mt2101ReceiptHandler());
        receiptHandlerList.add(new Mt8104ReceiptHandler());
        return receiptHandlerList;
    }

}
  • クライアント
public class Client {

    public static void main(String[] args) {
        //模拟回执
        List<Receipt> receiptList = ReceiptBuilder.generateReceiptList();
        for (Receipt receipt : receiptList) {
            //回执处理链对象
            ReceiptHandleChain receiptHandleChain = new ReceiptHandleChain();
            receiptHandleChain.handleReceipt(receipt);
        }
    }
}

メッセージMT2101を解析します:私はああ、MT2101のレシートメッセージだ
私はMT8104のレシートメッセージああ午前:メッセージのMT8104を解析

構造はまた、私たちを排除している場合、それ以外の責任の連鎖を処理することにより、新しい領収書は、単に追加するたびIReceiptHandler実装クラスをし、変更ReceiptHandlerContainerあなたは開閉の原則とプログラムの一貫性を保つためにしたい場合は、ハンドラコンテナは、あなたがする必要がありますすることができます調整ReceiptHandlerContainerハンドラ取得モードの、反射の仕方によって、指定されたパッケージで取得したすべてのIReceiptHandler実装クラス

すべての指定されたインターフェイスの実装クラスを取得するためのツールのクラスの本明細書中で使用される、反射、など

/**
 * @Description: 反射工具类
 * @Auther: wuzhazha
 */
public class ReflectionUtil {
    
    /**
     * 定义类集合(用于存放所有加载的类)
     */
    private static final Set<Class<?>> CLASS_SET;

    static {
        //指定加载包路径
        CLASS_SET = getClassSet("com.yaolong");
    }
    
    /**
     * 获取类加载器
     * @return
     */
    public static ClassLoader getClassLoader(){
        return Thread.currentThread().getContextClassLoader();
    }

    /**
     * 加载类
     * @param className 类全限定名称
     * @param isInitialized 是否在加载完成后执行静态代码块
     * @return
     */
    public static Class<?> loadClass(String className,boolean isInitialized) {
        Class<?> cls;
        try {
            cls = Class.forName(className,isInitialized,getClassLoader());
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        return cls;
    }

    public static Class<?> loadClass(String className) {
        return loadClass(className,true);
    }

    /**
     * 获取指定包下所有类
     * @param packageName
     * @return
     */
    public static Set<Class<?>> getClassSet(String packageName) {
        Set<Class<?>> classSet = new HashSet<>();
        try {
            Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".","/"));
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                if (url != null) {
                    String protocol = url.getProtocol();
                    if (protocol.equals("file")) {
                        String packagePath = url.getPath().replace("%20","");
                        addClass(classSet,packagePath,packageName);
                    } else if (protocol.equals("jar")) {
                        JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
                        if (jarURLConnection != null) {
                            JarFile jarFile = jarURLConnection.getJarFile();
                            if (jarFile != null) {
                                Enumeration<JarEntry> jarEntries = jarFile.entries();
                                while (jarEntries.hasMoreElements()) {
                                    JarEntry jarEntry = jarEntries.nextElement();
                                    String jarEntryName = jarEntry.getName();
                                    if (jarEntryName.endsWith(".class")) {
                                        String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
                                        doAddClass(classSet,className);
                                    }
                                }
                            }
                        }
                    }
                }
            }


        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return classSet;
    }

    private static void doAddClass(Set<Class<?>> classSet, String className) {
        Class<?> cls = loadClass(className,false);
        classSet.add(cls);
    }

    private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) {
        final File[] files = new File(packagePath).listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
            }
        });
        for (File file : files) {
            String fileName = file.getName();
            if (file.isFile()) {
                String className = fileName.substring(0, fileName.lastIndexOf("."));
                if (StringUtils.isNotEmpty(packageName)) {
                    className = packageName + "." + className;
                }
                doAddClass(classSet,className);
            } else {
                String subPackagePath = fileName;
                if (StringUtils.isNotEmpty(packagePath)) {
                    subPackagePath = packagePath + "/" + subPackagePath;
                }
                String subPackageName = fileName;
                if (StringUtils.isNotEmpty(packageName)) {
                    subPackageName = packageName + "." + subPackageName;
                }
                addClass(classSet,subPackagePath,subPackageName);
            }
        }
    }


    public static Set<Class<?>> getClassSet() {
        return CLASS_SET;
    }

    /**
     * 获取应用包名下某父类(或接口)的所有子类(或实现类)
     * @param superClass
     * @return
     */
    public static Set<Class<?>> getClassSetBySuper(Class<?> superClass) {
        Set<Class<?>> classSet = new HashSet<>();
        for (Class<?> cls : CLASS_SET) {
            if (superClass.isAssignableFrom(cls) && !superClass.equals(cls)) {
                classSet.add(cls);
            }
        }
        return classSet;
    }

    /**
     * 获取应用包名下带有某注解的类
     * @param annotationClass
     * @return
     */
    public static Set<Class<?>> getClassSetByAnnotation(Class<? extends Annotation> annotationClass) {
        Set<Class<?>> classSet = new HashSet<>();
        for (Class<?> cls : CLASS_SET) {
            if (cls.isAnnotationPresent(annotationClass)) {
                classSet.add(cls);
            }
        }
        return classSet;
    }

}

次の変換ReceiptHandlerContainer

public class ReceiptHandlerContainer {

    private ReceiptHandlerContainer(){}

    public static List<IReceiptHandler> getReceiptHandlerList(){
        List<IReceiptHandler> receiptHandlerList = new ArrayList<>();
        //获取IReceiptHandler接口的实现类
        Set<Class<?>> classList = ReflectionUtil.getClassSetBySuper(IReceiptHandler.class);
        if (classList != null && classList.size() > 0) {
            for (Class<?> clazz : classList) {
                try {
                    receiptHandlerList.add((IReceiptHandler)clazz.newInstance());
                } catch ( Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return receiptHandlerList;
    }

}

これまでのところ、完全に開閉の原則に沿って、プログラムは、領収書の新しいタイプの場合は、単に他の変更を行う必要がなく、新しいレシートプロセッサを追加します。次のように、新しく追加されたのMT6666受領

public class Mt6666ReceiptHandler implements IReceiptHandler {

    @Override
    public void handleReceipt(Receipt receipt, IReceiptHandleChain handleChain) {
        if (StringUtils.equals("MT6666",receipt.getType())) {
            System.out.println("解析报文MT6666:" + receipt.getMessage());
        }
        //处理不了该回执就往下传递
        else {
            handleChain.handleReceipt(receipt);
        }
    }
}


戦略モード+ノート

この事実、およびプログラムは、多くの類似点と相違点を超えていないハンドラクラスをマーク、カスタム注釈の方法により、開閉の原則に従うために、そのクラスは、地図に取得回収容器を反映し、ここでは繰り返しません


概要

またはこのブランチは、直感的あるいは効率的な中小企業の簡単な、のロジックを分岐する方法が決定された場合、他のスイッチケース。複雑な操作のために、技術を適切なモードを使用して、ロジックを多分岐、コードより明確に、簡単に維持することができるが、同時に、クラスやメソッドの数が乗算されます。当社は、事業の完全な分析を行うデザイン・パターンに1を避けるため、過エンジニアリングを回避する必要があります!

おすすめ

転載: www.cnblogs.com/DiDi516/p/11787257.html