「Patternの設計」構造アレイ


06.アダプタモード

  • モード
  • 既存コードをクライアント使用インタフェースのインプリメンテーションに変換
  • では、クライアントが使用するインタフェースに従わずに既存のコードを再利用できます.
  • オブジェクトアダプタとクラスアダプタに分かれています.

  • 実施方法

    // Target
    interface Target {
      void operation();
    }
    
    // Adaptee
    public class Adaptee {
      
      public void specificOperation() {
        // do something...
      }
      
    }
    
    // Object Adapter
    public class ObjectAdapter implements Target {
    
      private final Adaptee adaptee;
    
      public ObjectAdapter(Adaptee adaptee) {
        this.adaptee = adaptee;
      }
    
      @Override
      public void operation() {
        adaptee.specificOperation();
      }
      
    }
    
    // Class Adapter
    public class ClassAdapter extends Adaptee implements Target {
    
      @Override
      public void operation() {
        super.specificOperation();
      }
    
    }
    public static void main(String[] args) {
      Target targetObjectAdapter = new ObjectAdapter(new Adaptee());
      Target targetClassAdapter = new ClassAdapter();
    
      targetObjectAdapter.operation();
      targetClassAdapter.operation();
    }

    メリットとデメリット


    長所

  • は、既存のコードを変更することなく、必要なインタフェースインプリメンテーションを作成し、再使用することができる.
  • の既存のコードが行う作業と、特定のインタフェースインプリメンテーションに変換される作業を異なるクラスに分けて管理することができる.
  • 短所

  • の新しいクラスがあれば、複雑さが増す可能性があります.
    場合によっては、既存のコードを変更してインタフェースを実装するのは良い選択かもしれません.
  • 07.ブリッジモード

  • 抽象と具体的な分離モード
  • コンポーネント
  • を使用
  • の階層の場合と比較して、各階層は独立した階層に発展することができます.
  • から抽象層を部分的に分離し、それぞれ独立して変形し、拡張可能にする.

  • 実施方法

    // Abstraction
    public class Shape {
    
      private final Color color;
      private final String name;
    
      public Shape(Color color, String name) {
        this.color = color;
        this.name = name;
      }
    
      public void printInfo() {
        System.out.printf("%s %s\n", color.getValue(), this.name);
      }
      
    }
    
    // Refined Abstraction 1
    public class Triangle extends Shape {
    
      public Triangle(Color color) {
        super(color, "triangle");
      }
    
      // 기능 추가...
      
    }
    
    // Refined Abstraction 1
    public class Pentagon extends Shape {
    
      public Triangle(Color color) {
        super(color, "pentagon");
      }
    
      // 기능 추가...
    
    }
    // Implementation
    public interface Color {
      String getValue();
    }
    
    // Concrete Implementation 1
    public class Green implements Color {
      public void getValue(){
        return "green";
      }
    }
    
    // Concrete Implementation 2
    public class Red implements Color {
      public void getValue(){
        return "red";
      }
    }
    public static void main(String[] args) {
      Shape triangle = new Triangle(new Red());
      triangle.printInfo();
    
      Shape pentagon = new Pentagon(new Green());
      pentagon.printInfo();
    }

    メリットとデメリット


    長所

  • 抽象コードは、特定のコードを変更することなく独立して拡張できます.(OCP)
  • 抽象コードは、特定のコードから分離することができる.(SRP)
  • 短所

  • 階層が増加し、複雑さが増加する可能性があります.
  • 08.複合モード

  • グループ全体の個々のオブジェクトを個々のオブジェクトと同じ処理を行うモード.
  • クライアントの場合、「全体」または「部分」またはすべての同じ構成部品と識別できる階層が作成されます.(Part-Whole Hierarchy)

  • 実施方法

    // Component
    public interface Validator {
      void validate(String input);
    }
    
    // Leaf 1
    public class EmptyValidator implements Validator {
      
      @Override
      public void validate(String input) {
        if (isEmpty(input)) {
          throw new IllegalArgumentException("input must not be empty");
        }
      }
    
      private boolean isEmpty(String input) {
        return input == null || input.isEmpty();
      }
    }
    
    // Leaf 2
    public class InputPatternValidator implements Validator {
      
      private static final Pattern PATTERN = Pattern.compile("^\\d+ [-+*/] \\d+$");
    
      @Override
      public void validate(String input) {
        if (!PATTERN.matcher(input).matches()) {
          throw new IllegalArgumentException("invalid input pattern");
        }
      }
    }
    
    // Composite
    public class CompositeValidator implements Validator {
    
      private final List<Validator> validators;
    
      public CompositeValidator(Validator... validators) {
        this.validators = Arrays.asList(validators);
      }
    
      @Override
      public void validate(String input) {
        validators.forEach(validator -> validator.validate(input));
      }
    }
    public static void main(String[] args) {
      Validator validator =  new CompositeValidator(new EmptyValidator(), new InputPatternValidator());
      validator.validate("10 + 25");
    }

    メリットとデメリット


    長所

  • は、複雑なツリー構造を容易に使用することができる.
  • 多形性および再帰を利用することができる.
  • クライアントコードを変更せずに、新しい別名タイプを追加できます.
  • 短所


    共通インタフェースを定義する必要があるため、
  • ツリーを作成する必要があるため、一般化しすぎる場合があります.
  • 09.装飾図案

  • モード
  • 、既存のコードを変更せずに追加機能を追加
    「継承」(
  • )ではなく「委任」(Delegation)を使用して、実行時に追加機能を追加することもできます.
  • 委任は、ある動作を委任関係のオブジェクトに渡すことを意味する.コンビネーション+転送といえる.
  • Decoratorの場合、Wrapperとも呼ばれます.

  • 実施方法

    // Component
    interface ChristmasTree {
      String decorate();
    }
    
    // ConcreteComponent
    public class DefaultChristmasTree implements ChristmasTree {
      
      @Override
      public String decorate() {
        return "Christmas tree";
      }
      
    }
    // Decorator
    public class TreeDecorator implements ChristmasTree {
      
      private final ChristmasTree christmasTree;
    
      public TreeDecorator(ChristmasTree christmasTree) {
        this.christmasTree = christmasTree;
      }
    
      @Override
      public String decorate() {
        return christmasTree.decorate();
      }
      
    }
    
    // Concrete Decorator 1
    public class LightsTreeDecorator extends TreeDecorator {
    
      public LightsTreeDecorator(ChristmasTree christmasTree) {
        super(christmasTree);
      }
      
      @Override
      public String decorate() {
        return super.decorate() + addLights();
      }
    
      private String addLights() {
        return " with Lights";
      }
      
    }
    
    // Concrete Decorator 2
    public class FlowersTreeDecorator extends TreeDecorator {
    
      public FlowersTreeDecorator(ChristmasTree christmasTree) {
        super(christmasTree);
      }
    
      @Override
      public String decorate() {
        return super.decorate() + addFlowers();
      }
    
      private String addFlowers() {
        return " with Flowers";
      }
      
    }
    public static void main(String[] args) {
      ChristmasTree tree = new FlowersTreeDecorator(new LightsTreeDecorator(new DefaultChristmasTree()));
    
      // Christmas tree with Lights with Flowers 
      System.out.println("tree: " + tree.decorate()); 
    }

    メリットとデメリット


    長所

  • は、新しいクラスを作成する必要がなく、既存の機能を組み合わせることができます.
  • コンパイル時ではなく、実行時に機能を動的に変更できます.
  • 短所

  • デコーダを組み合わせたコードは複雑になる可能性があります.
  • に役立つ


    Wrapper
  • InputStream、OutputStream、Reader、Writerジェネレータを使用
  • java.util.Collectionsが提供する方法を使用するWrapper(checkedで始まるかsynchronizedで始まる)
  • javax.servlet.http.HttpServletRequest/ResponseWrapper
  • 10.グループ化モード

  • の複雑なサブシステム依存性を低減する方法.
  • クライアントが使用する必要がある複雑なサブシステム依存性は、単純なインタフェースとして抽象化することができる.
  • グラムの林コードで言われているきれいな境界と似ているように見えます.
  • Facadeは「建物の正面」という意味です.

  • 実施方法

    // Facade
    public class GoOffice {
    
      public void goToWork() {
        Wash wash = new Wash();
        Breakfast breakfast = new Breakfast();
        Move move = new Move();
    
        wash.brushTeeth();
        wash.shower();
        breakfast.eat();
        breakfast.water();
        move.bus();
      }
      
    }
    
    // Sub System 1
    public class Wash {
      
      public void brushTeeth() {
        System.out.println("Brush my teeth");
      }
    
      public void shower() {
        System.out.println("Take a shower");
      }
      
    }
    
    // Sub System 2
    public class Breakfast {
      
      public void eat() {
        System.out.println("Have breakfast");
      }
    
      public void water() {
        System.out.println("Drink water");
      }
      
    }
    
    // Sub System 3
    public class Move {
      
      public void bus() {
        System.out.println("Take the bus");
      }
      
    }
    public static void main(String[] args) {
      GoOffice goOffice = new GoOffice();
      goOffice.goToWork();
    }

    メリットとデメリット


    長所

  • サブシステムへの依存性は、1つの場所に集中することができる.
  • 短所

  • シードクラスは、サブシステムへのすべての依存性を有する.
  • に役立つ

  • SLF4J (Simple Logging Facade for Java)
  • 11.フローティングモード

  • オブジェクトを軽くしてメモリの使用を減らすモード.
  • は、頻繁に変化する属性(または外部属性、外部属性)と不変の属性(または内部属性、内部属性)を分離および再利用することによって、メモリの使用を低減することができる.
  • で再利用されるオブジェクトは、共有されているため、可変でなければなりません.
  • の共通要素を共有してメモリを節約するため、キャッシュと見なすことができます.

  • 実施方法

    // Flyweight
    public final class Font {
    
      private final String family;
      private final int size;
    
      public Font(String family, int size) {
        this.family = family;
        this.size = size;
      }
    
      public String getFamily() {
        return family;
      }
    
      public int getSize() {
        return size;
      }
      
    }
    
    // Flyweight Factory
    public class FontFactory {
    
      private static final Map<String, Font> CACHE = new HashMap<>();
    
      public static Font getFont(String font) {
        Font result = CACHE.get(font);
        if (result == null) {
          String[] split = font.split(":");
          result = new Font(split[0], Integer.parseInt(split[1]));
          cache.put(font, result);
        }
        
        return result;
      }
      
    }
    public static void main(String[] args) {
        Font font1 = FontFactory.getFont("Arial:12");
        Font font2 = FontFactory.getFont("Arial:12");
    
        assert font1 == font2;
    }

    メリットとデメリット


    長所

  • アプリケーションで使用されるメモリを削減できます.
  • 短所

  • コードの複雑さが増加しました.
  • に役立つ

  • Integer.valueOf(int),-128~127キャッシュ.
  • 12.エージェント・モード


    特定のオブジェクトへのアクセスを制御または追加するための
  • モード.
  • は、初期化の遅延、アクセス制御、ログ記録、キャッシュなどに使用することができる.

  • 実施方法

    // Subject
    public interface OrderService {
      void order();
    }
    
    // RealSubject
    public class DefaultOrderService implements OrderService {
    
      @Override
      public void order() {
        System.out.println("주문하기...");
      }
      
    }
    
    // Proxy
    public class OrderServiceProxy implements OrderService {
    
      private OrderService orderService;
    
      @Override
      public void startGame() {
        long before = System.currentTimeMillis();
        
        if (this.orderService == null) {
          this.orderService = new DefaultOrderService();
        }
    
        orderService.order();
    
        System.out.println(System.currentTimeMillis() - before);
      }
      
    }
    public static void main(String[] args) {
      OrderService orderService = new OrderServiceProxy();
      orderService.order();
    }

    メリットとデメリット


    長所

  • は、既存のコードを変更することなく、新しい機能を追加することができる.
  • は、既存のコードが行う作業のみを維持します.
  • 機能の追加や遅延初期化など様々な方法で使用できます.
  • 短所

  • コードの複雑さが増加しました.
  • に役立つ

  • Javaダイナミックエージェント、java.lang.reflect.Proxy
  • Spring AOP
  • Decoratorモードとエージェントモード

  • デコーダモードの目的は、Real Classの機能に他の機能を追加(拡張)することである.
  • エージェントモードの目的はReal Classへのアクセスを制御することである.