Java設計モード(ポリシーモード)

12892 ワード

ポリシー・モード紹介ポリシー・モード定義
戦略モード(Strategy Pattern)は、抽象的な戦略クラスのサブクラスとして、様々なアルゴリズムを特定のクラスにカプセル化し、それらを交換できるようにする.クライアントは、どのアルゴリズムを使用するかを自分で決定できます.
ポリシーパターンクラス図
ポリシー・モードの役割区分
Strategyポリシーインタフェースまたは(抽象ポリシークラス)は、ポリシー実行インタフェースConcreteStrategyの特定のポリシークラスContextコンテキストクラスを定義し、特定のポリシークラスのインスタンスを持ち、関連するアルゴリズムの呼び出しを担当します.
ポリシー・モード・インスタンス解析の典型的なポリシー・モード実装
ポリシーインタフェース、ポリシー実行インタフェースの定義
package com.jasongj.strategy;

public interface Strategy {

  void strategy(String input);

}

具体的なポリシークラス、ポリシーインタフェースを実現し、具体的なアルゴリズムを提供する
package com.jasongj.strategy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@com.jasongj.annotation.Strategy(name="StrategyA")
public class ConcreteStrategyA implements Strategy {

  private static final Logger LOG = LoggerFactory.getLogger

(ConcreteStrategyB.class);

  @Override
  public void strategy(String input) {
    LOG.info("Strategy A for input : {}", input);
  }

}
package com.jasongj.strategy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@com.jasongj.annotation.Strategy(name="StrategyB")
public class ConcreteStrategyB implements Strategy {

  private static final Logger LOG = LoggerFactory.getLogger(ConcreteStrategyB.class);

  @Override
  public void strategy(String input) {
    LOG.info("Strategy B for input : {}", input);
  }

}

Contextクラスは、特定のポリシークラスのインスタンスを持ち、特定のアルゴリズムの呼び出しを担当します.
package com.jasongj.context;

import com.jasongj.strategy.Strategy;

public class SimpleContext {

  private Strategy strategy;

  public SimpleContext(Strategy strategy) {
    this.strategy = strategy;
  }

  public void action(String input) {
    strategy.strategy(input);
  }

}

クライアントは、特定のポリシークラスをインスタンス化し、Contextクラスに転送し、Contextによって特定のアルゴリズムを統一的に呼び出すことができます.
package com.jasongj.client;

import com.jasongj.context.SimpleContext;
import com.jasongj.strategy.ConcreteStrategyA;
import com.jasongj.strategy.Strategy;

public class SimpleClient {

  public static void main(String[] args) {
    Strategy strategy = new ConcreteStrategyA();
    SimpleContext context = new SimpleContext(strategy);
    context.action("Hellow, world");
  }

}

Annotationおよび単純ファクトリ・モードを使用したポリシー・モードの強化
上記の実装では、クライアントは、具体的にどのポリシーを使用するかを決定し、他のポリシーを交換する必要がある場合、クライアントのコードを変更する必要があることを示す必要がある.この問題を解決するには、クライアントがポリシークラスのインスタンス化プロセスを知る必要がなく、具体的にどのポリシーが使用されるかを知る必要もないように、単純なファクトリを使用することが好ましい.『Java設計モード(一)単純ファクトリモードは単純ではない』で述べたように,単純ファクトリの実現方式は比較的多く,『Javaシリーズ(一)Annotation(注釈)』で紹介したAnnotation手法と組み合わせることができる.Annotationと単純ファクトリモードを使用したContextクラスは次のとおりです.
package com.jasongj.context;

import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jasongj.strategy.Strategy;

public class SimpleFactoryContext {

  private static final Logger LOG = LoggerFactory.getLogger(SimpleFactoryContext.class);
  private static Map<String, Class> allStrategies;

  static {
    Reflections reflections = new Reflections("com.jasongj.strategy");
    Set<Class<?>> annotatedClasses =
        reflections.getTypesAnnotatedWith(com.jasongj.annotation.Strategy.class);
    allStrategies = new ConcurrentHashMap<String, Class>();
    for (Class<?> classObject : annotatedClasses) {
      com.jasongj.annotation.Strategy strategy = (com.jasongj.annotation.Strategy) classObject
          .getAnnotation(com.jasongj.annotation.Strategy.class);
      allStrategies.put(strategy.name(), classObject);
    }
    allStrategies = Collections.unmodifiableMap(allStrategies);
  }

  private Strategy strategy;

  public SimpleFactoryContext() {
    String name = null;
    try {
      XMLConfiguration config = new XMLConfiguration("strategy.xml");
      name = config.getString("strategy.name");
      LOG.info("strategy name is {}", name);
    } catch (ConfigurationException ex) {
      LOG.error("Parsing xml configuration file failed", ex);
    }

    if (allStrategies.containsKey(name)) {
      LOG.info("Created strategy name is {}", name);
      try {
        strategy = (Strategy) allStrategies.get(name).newInstance();
      } catch (InstantiationException | IllegalAccessException ex) {
        LOG.error("Instantiate Strategy failed", ex);
      }
    } else {
      LOG.error("Specified Strategy name {} does not exist", name);
    }

  }

  public void action(String input) {
    strategy.strategy(input);
  }

}

以上の実装から,単純なファクトリクラスは単独で作成されていないが,単純なファクトリモデルの設計思想と実装方法が溶け込んでいることがわかる.クライアント呼び出し方式は次のとおりです.
package com.jasongj.client;

import com.jasongj.context.SimpleFactoryContext;

public class SimpleFactoryClient {

  public static void main(String[] args) {
    SimpleFactoryContext context = new SimpleFactoryContext();
    context.action("Hellow, world");
  }

}

上記のコードから,単純なファクトリモードを導入すると,クライアントは具体的なポリシークラスを直接インスタンス化する必要がなくなり,どのようなポリシーを使用すべきかを判断する必要もなく,ポリシーの切り替えに容易に対応できる.
ポリシー・モード分析ポリシー・モードの利点
ポリシー・モードは、ユーザーが既存のシステムを変更することなくアルゴリズム(ポリシー)を選択し、新しいアルゴリズム(ポリシー)を柔軟に追加できる「開閉原則」の完璧なサポートを提供します.ポリシー・モードは、Contextクラスによって、特定のポリシー・クラス(アルゴリズム・ファミリー)を管理する方法を提供します.単純ファクトリモードとAnnotationを組み合わせることで,ポリシーモードはクライアントコードを変更することなくアルゴリズム(ポリシー)を容易に切り替えることができる.
ポリシー・モードの欠点
従来のポリシー・モードの実装では、クライアントはすべての特定のポリシー・クラスを知っていて、どのポリシー・クラスを使用するかを決定する必要があります.しかし、本明細書で説明するAnnotationと単純なファクトリ・モードを組み合わせることで、この問題が適切に使用されない場合、ポリシー・モードは多くの具体的なポリシー・クラスのインスタンスを作成する可能性がありますが、上記のJava設計モード(十一)享元モードで説明した享元モードを使用することで、オブジェクトの数を効果的に減らすことができます.
ポリシー・モードが遵守されていないOOPの原則
遵守されたOOPの原則
依存逆置原則ディミット法則リ氏置換原則インタフェース隔離原則単一職責原則開閉原則