はじめに#
物流業界は、典型的には、サードパーティシステムにおけるデータストリームをEDIメッセージ(XMLフォーマット)を受信し受信と送信を含む、各EDIがパケットを送信、関連する後続のレシートを受信する(状態識別)。いくつかのタイプは、本明細書に領収書を列挙:MT1101、MT2101、MT4101、MT8104、MT8105、MT9999
システムを異なる肯定応答パケットを受信した後、実行は、ビジネスロジックに対応する処理します。ここではもちろん、実際のビジネス・シナリオとそう一般的ではない、プレゼンテーションのケースのための受信処理
- 領収書のクラスをシミュレート
コピー
`@Data
パブリッククラス受領{
/**
* 回执信息
*/
String message;
/**
* 回执类型(`MT1101、MT2101、MT4101、MT8104、MT8105、MT9999`)
*/
String type;
} ``
- 領収書ジェネレータのシミュレーション
コピー
`パブリッククラス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構造があまりにも肥大化に見えるではないでしょう。枝は、より多くの追加の各領収書の種類になります場合は領収書の種類は他に、上昇した場合、上記の例では、あなたが、もし、他のブランチを変更または追加する必要があるため開閉(拡張子に開放の原則に違反して近くに修正)
戦略モード+地図辞典#
私たちは、そのクライアントの使用には依存しないアルゴリズムと独立した変更を、クライアントは単に政策のインターフェースに依存しているように、お互いを置き換えることができ、戦略パターンの目的は、一連のアルゴリズムをカプセル化することであることを知って、彼らは共通しています。上記のシナリオでは、クライアントはまだ方針の選択のためのいくつかのif-elseロジックを記述する必要があることを、我々は様々な戦略を抽出するために、ビジネスロジックの場合、他の支店を置くことができますが、それは避けられない、我々は工場出荷時に、このロジックを抽出することができますどこへ行くクラス、これは戦略パターン+シンプル工場、次のようにコードがあり、
- policyインターフェイス
コピー
`/ **
- @description:領収書の処理戦略インタフェース
@Auther:wuzhazha
* /
パブリックインターフェイスIReceiptHandleStrategy {空handleReceipt(領収書の領収書);
} `
- 特定のハンドラであるポリシー・インターフェース・クラス、
コピー
`パブリッククラスMt2101ReceiptHandleStrategyが実装IReceiptHandleStrategy {
@Override
public void handleReceipt(Receipt receipt) {
System.out.println("解析报文MT2101:" + receipt.getMessage());
}
}
パブリッククラスMt1101ReceiptHandleStrategy実装IReceiptHandleStrategy {
@Override
public void handleReceipt(Receipt receipt) {
System.out.println("解析报文MT1101:" + receipt.getMessage());
}
}
パブリッククラスMt8104ReceiptHandleStrategy実装IReceiptHandleStrategy {
@Override
public void handleReceipt(Receipt receipt) {
System.out.println("解析报文MT8104:" + receipt.getMessage());
}
}
パブリッククラスMt9999ReceiptHandleStrategy実装IReceiptHandleStrategy {
@Override
public void handleReceipt(Receipt receipt) {
System.out.println("解析报文MT9999:" + receipt.getMessage());
}
} `
- ポリシーコンテキストクラス(ポリシーホルダーインタフェース)
コピー
`/ **
- @description:コンテキストクラス、ホールド戦略インターフェイス
@Auther:wuzhazha
* /
publicクラスReceiptStrategyContext {プライベートIReceiptHandleStrategy receiptHandleStrategy。
/ **- ポリシー設定インターフェイス
- @param receiptHandleStrategy
* /
公共ボイドsetReceiptHandleStrategy(IReceiptHandleStrategy receiptHandleStrategy){
this.receiptHandleStrategy = receiptHandleStrategy。
}
公共のボイドhandleReceipt(領収書の領収書){
場合(receiptHandleStrategy = nullを!){
receiptHandleStrategy.handleReceipt(領収書)。
}
}
} `戦略工場
コピー
`/ **
- @description:戦略工場
@Auther:wuzhazha
* /
パブリッククラスReceiptHandleStrategyFactory {プライベートReceiptHandleStrategyFactory(){}
パブリック静的IReceiptHandleStrategy getReceiptHandleStrategy(文字列receiptType){
IReceiptHandleStrategy receiptHandleStrategy = NULL;
(StringUtils.equals( "MT2101"、receiptType)){もし
receiptHandleStrategy =新しいMt2101ReceiptHandleStrategy()。
}他(StringUtils.equals( "MT8104"、receiptType)){もし
receiptHandleStrategy =新しいMt8104ReceiptHandleStrategy()。
}
receiptHandleStrategyを返します。
}
} `クライアント
コピー
`publicクラス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
* /
パブリッククラスReceiptHandleStrategyFactory {プライベート静的地図<文字列、IReceiptHandleStrategy> receiptHandleStrategyMap。
プライベートReceiptHandleStrategyFactory(){
this.receiptHandleStrategyMap =新規HashMapの<>();
this.receiptHandleStrategyMap.put( "MT2101"、新Mt2101ReceiptHandleStrategy());
this.receiptHandleStrategyMap.put( "MT8104"、新Mt8104ReceiptHandleStrategy());
}パブリック静的IReceiptHandleStrategy getReceiptHandleStrategy(文字列receiptType){
リターンreceiptHandleStrategyMap.get(receiptType)。
}
} `
場合は、他の新しい領収書は、単に新しい受信処理戦略を追加、および変更するたびに戦略+シンプルなプラントソリューションのモードの形質転換後、我々は構造を排除しているReceiptHandleStrategyFactory
地図のコレクションを。あなたは開閉の原則とプログラムの一貫性を保つためにしたい場合は、我々は調整する必要がReceiptHandleStrategyFactory
戦略を処理して取得モードを、反射の仕方によって、指定されたパッケージの下のすべてを取得するIReceiptHandleStrategy
実装クラスは、ディクショナリマップに入ります。
責任パターンのチェーン#
Chain of Responsibilityパターンは、オブジェクト行動パターンです。責任パターン、自宅でそれらの各オブジェクト参照の多くのオブジェクトの鎖に一緒に接続されたチェーンを形成します。チェーン決意処理要求に特定のオブジェクトまで、この連鎖移動要求です。発行されたこの要求クライアントは、クライアントの場合に責任の動的なシステムの再編成や分布に影響を与えることができないように、最終的にリクエストを処理しているチェーン上のどのオブジェクトを知りません
- 領収書の処理インタフェース
コピー
`/ **
- @description:インタフェースの処理を抽象領収書
@Auther:wuzhazha
* /
パブリックインターフェイスIReceiptHandler {空handleReceipt(領収書の領収書、IReceiptHandleChain handleChain)。
} `
- 責任のチェーンインタフェース
コピー
`/ **
- @description:責任のチェーンインタフェース
@Auther:wuzhazha
* /
パブリックインターフェイスIReceiptHandleChain {空handleReceipt(領収書の領収書);
} `責任のチェーンインタフェースの実装クラス
コピー
`/ **
- @description:責任の実装クラスのチェーン
@Auther:wuzhazha
* /
publicクラスReceiptHandleChain実装IReceiptHandleChain {
//記録し、現在の位置ハンドラ
プライベートint型のインデックス= 0;
//セットハンドラ
プライベート静的リストreceiptHandlerList; {静的
//コンテナからオブジェクトのプロセッサを取得
receiptHandlerList ReceiptHandlerContainer.getReceiptHandlerList =();
}@Override
ます。public void handleReceipt(領収書の領収書){
場合(receiptHandlerList = NULL && receiptHandlerList.size()> 0!){
場合(インデックス= receiptHandlerList.size()!){
IReceiptHandler receiptHandler = receiptHandlerList.get(インデックス++);
receiptHandler.handleReceipt(レシート、この);
}
}
}
} `特定のレシートハンドラ
コピー
`パブリッククラスMt2101ReceiptHandlerが実装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);
}
}
}
パブリッククラスMt8104ReceiptHandler実装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
* /
パブリッククラスReceiptHandlerContainer {プライベートReceiptHandlerContainer(){}
パブリック静的リスト
getReceiptHandlerList(){
リストreceiptHandlerList =新しいArrayListを<>();
receiptHandlerList.add(新しいMt2101ReceiptHandler());
receiptHandlerList.add(新しいMt8104ReceiptHandler());
receiptHandlerListを返します。
}
} `
- クライアント
コピー
`publicクラス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クラスReflectionUtil {- (すべてのロードされたクラスの記憶のための)クラスの定義済みセット
* /
プライベート静的最終セット<クラス<>> CLASS_SET ?;
{静的
/ **
//指定された装填パッケージパス
CLASS_SET = getClassSet( "com.yaolong");
}- クラスローダを取得します。
- @return
* /
パブリック静的クラスローダのgetClassLoader(){
リターンにThread.currentThread()getContextClassLoader()。
}
- ロードクラス
- @param classNameの完全修飾クラス名
- @param isInitialized静的ブロックを実行するかどうかをローディングが完了した後
- @return
* /
パブリック静的クラスのloadClass(クラス名文字列、ブールisInitialized){<?>
クラスCLS <?>。
試す{
CLS = Class.forNameの(クラス名、isInitialized、のgetClassLoader())。
}キャッチ(ClassNotFoundExceptionが電子){
新規のRuntimeException(e)を投げます。
}
CLSを返します。
}
パブリック静的クラスのloadClass(文字列クラス名){<?>
/ **
リターンはloadClass(classNameの、真の);
}- パッケージを指定したすべてのクラスを取得します。
- @paramのpackageName
@return
* /
パブリック静的に設定<クラス<>> getClassSet(文字列のpackageName){?
設定<クラス<>> classSet =新しいHashSetの<>();?
試し{
列挙。のURL =のgetClassLoader()getResources(packageName.replace( "/ ")"。");
一方、(urls.hasMoreElements()){
URL URL = urls.nextElement()。
(もし!URL = NULL){
String型のプロトコル= url.getProtocol();
(protocol.equals( "ファイル"))なら、{
文字列packagePath = url.getPath()( "20%"、 "")を置き換えます。
addClass(classSet、packagePath、のpackageName)。
}他(protocol.equals( "JAR")){場合
はJarURLConnectionはJarURLConnection =(はJarURLConnection)url.openConnection();
もし(!はJarURLConnection = NULL){
するJarFile jarファイル= jarURLConnection.getJarFile();
jarファイル(もし!
jarEntries = jarFile.entries()。
一方、(jarEntries.hasMoreElements()){
たJarEntryたJarEntry = jarEntries.nextElement()。
ストリングjarEntryName = jarEntry.getName()。
IF(jarEntryName.endsWith( "クラス")){
文字クラス名= jarEntryName.substring(0、jarEntryName.lastIndexOf()"。 ")でReplaceAll("/"、 "")。
doAddClass(classSet、クラス名)。
}
}
}
}
}
}
}}キャッチ(IOExceptionを電子){
新規のRuntimeException(e)を投げます。
}
classSetを返します。
}
プライベートの静的な無効doAddClass(セット<クラス<>> classSet、文字列クラス名?){
クラス<> CLS =はloadClass(classNameの、偽の);?
classSet.add(CLS)。
}プライベートの静的な無効addClass(セット<クラス<?>> classSet、文字列packagePath、文字列のpackageName){
最後のファイル[]ファイル=新しいファイル(packagePath).listFiles(新しいFileFilterの(){
@Override
国民が)(ファイルのファイルを受け入れるブール{
リターン(file.isFile()&& file.getName()endsWith()。 "クラス")|| file.isDirectory();
}
})。
{:(ファイルファイルファイル)のための
文字列fileNameに= file.getName();
(file.isFile()){もし
文字クラス名= fileName.substring( "" 0、fileName.lastIndexOf())。
IF(StringUtils.isNotEmpty(のpackageName)){
クラス名=のpackageName + "" +クラス名;
}
doAddClass(classSet、クラス名)。
{}他
ストリングsubPackagePath =ファイル名;
IF(StringUtils.isNotEmpty(packagePath)){
subPackagePath = packagePath + "/" + subPackagePath。
}
文字列subPackageName =ファイル名;
IF(StringUtils.isNotEmpty(のpackageName)){
subPackageName =のpackageName + "" + subPackageName;
}
addClass(classSet、subPackagePath、subPackageName)。
}
}
}?パブリック静的セット<クラス<>> getClassSet(){
/ **
戻りCLASS_SET。
}- アプリケーションパッケージのすべての親クラスのサブクラス(またはインタフェース)(または実装クラス)の名前を取得します。
- @paramスーパー
- @return
* /
パブリック静的に設定<クラス<>> getClassSetBySuper(クラス<>スーパー?){?
設定<クラス<>> classSet =新しいHashSetの<>();?
(<?>クラスCLS:CLASS_SET)について{
場合(!superClass.isAssignableFrom(CLS)&& superClass.equals(CLS)){
classSet.add(CLS)。
}
}
classSetを返します。
}
- 注釈付きクラスでアプリケーションパッケージ名を取得します。
- @param annotationClass
- @return
* /
?パブリック静的に設定<クラス<>> getClassSetByAnnotation(?クラス<拡張注釈> annotationClass){
?設定<クラス<>> classSet =新しいHashSetの<>();
(<?>クラスCLS:CLASS_SET)用{
IF(cls.isAnnotationPresent(annotationClass)){
classSet.add(CLS)。
}
}
classSetを返します。
}
- (すべてのロードされたクラスの記憶のための)クラスの定義済みセット
} `
次の変換ReceiptHandlerContainer
コピー
`パブリッククラス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受領
コピー
`パブリッククラスMt6666ReceiptHandlerが実装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を避けるため、避けオーバーエンジニアリング!