ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Strategy
    Modeling/DesignPattern 2020. 2. 26. 00:42

    1. Overview

    Strategy pattern allows us to encapsulate an algorithm in a class. So we can configure our context or main object with an object of this class, to change the algorithm used to perform given operation. This is helpful if you have many possible variations of an algorithm. A good indication for the applicability of strategy pattern is if we find different algorithms/behaviors in our methods that are selected with conditional statements like if-else or switch-case.

    Strategy classes are usually implemented in an inheritance hierarchy so that we can choose any one implementation and it'll work with our main object/context as the interface is the same for all implementations.

    2. Description

    2.1 Implementation

    • We start by defining strategy interface which is used by our main/context class. Context class provides strategy with all the data that it needs
    • We provide implementations for various algorithms by implementing strategy interface a class per algorithm
    • Our context class provides a way to configure it with one of the strategy implementations. Client code will create a context with one of the strategy object

    2.2 Consideration

    2.2.1 Implementation

    • We can implement our context in a way where strategy object is optional. This makes context usable for client codes who do not want to deal with concrete strategy objects.
    • Strategy objects should be given all the data they need as arguments to its method. If number of arguments is high then we can pass strategy an interface reference which queries for data. Context object can implement this interface and pass itself to strategy
    • Strategies typically end up being stateless objects making them perfect candidates for sharing between context objects

    2.2.2. Design

    • Strategy implementations can make use of inheritance to factor out common parts of algorithms in base classes making child implementations simpler
    • Since strategy objects often end up with no state of their own, we can use flyweight pattern to share them between multiple context objects.

    2.3 Pitfalls

    Since client code configures context object with appropriate strategy object, clients know about all implementations of strategy. Introducing new algorithm means changing client code as well.

    3. Usage

    3.1 java.util.Comparator

    4. Comparison with State

    Strategy State
    We create a class per algorithm In state pattern, we have a class per state
    Strategy objects do not need to know about each other If states are responsible for triggering state transitions then they have to know about at least next state

    5. Example

    //Strategy
    interface OrderPrinter {
        void print(Collection<Order> orders);
    }
    
    //Concrete strategy
    class SummaryPrinter implements OrderPrinter{
        @Override
        public void print(Collection<Order> orders) {
            System.out.println("******************** Summary Report ***********************");
            Iterator<Order> iterator = orders.iterator();
            double total = 0;
            for (int i = 0; iterator.hasNext(); i++) {
                Order order = iterator.next();
                System.out.println(i + ". " + order.getId() + "\t" + order.getDate() + "\t" + order.getItems().size() + "\t" + order.getTotal());
                total += order.getTotal();
            }
            System.out.println("**********************************");
            System.out.println("\t\t\t Total " + total);
        }
    }
    class DetailPrinter implements OrderPrinter {
    
        @Override
        public void print(Collection<Order> orders) {
            System.out.println("************* Detail Report ***********");
            Iterator<Order> iter = orders.iterator();
            double total = 0;
            for(int i=1;iter.hasNext();i++) {
                double orderTotal = 0;
                Order order = iter.next();
                System.out.println(i+". "+order.getId()+" \t"+order.getDate());
                for(Map.Entry<String, Double> entry : order.getItems().entrySet()) {
                    System.out.println("\t\t"+entry.getKey()+"\t"+entry.getValue());
                    orderTotal+=entry.getValue();
                }
                System.out.println("----------------------------------------");
                System.out.println("\t\t Total  "+orderTotal);
                System.out.println("----------------------------------------");
                total += orderTotal;
            }
            System.out.println("----------------------------------------");
            System.out.println("\tGrand Total "+total);
        }
    }
    class Order {
    
        private String id;
    
        private LocalDate date;
    
        private Map<String, Double> items = new HashMap<>();
    
        private double total;
    
        public Order(String id) {
            this.id = id;
            date = LocalDate.now();
        }
    
        public String getId() {
            return id;
        }
    
        public LocalDate getDate() {
            return date;
        }
    
        public Map<String, Double> getItems() {
            return items;
        }
    
        public void addItem(String name, double price) {
            items.put(name, price);
            total+= price;
        }
    
        public double getTotal() {
            return total;
        }
    
        public void setTotal(double total) {
            this.total = total;
        }
    }
    //Context
    class PrintService {
        private OrderPrinter printer;
        public PrintService(OrderPrinter printer) {
            this.printer = printer;
        }
        public void printOrders(LinkedList<Order> orders) {
            printer.print(orders);
        }
    }
    public class Client {
        private static LinkedList<Order> orders = new LinkedList<>();
        public static void main(String[] args) {
            createOrders();
    //        PrintService service = new PrintService(new SummaryPrinter());
            PrintService service = new PrintService(new DetailPrinter());
            service.printOrders(orders);
        }
        private static void createOrders() {
            Order o = new Order("100");
            o.addItem("Soda", 2);
            o.addItem("Chips", 10);
            orders.add(o);
    
            o = new Order("200");
            o.addItem("Cake", 20);
            o.addItem("Cookies", 5);
            orders.add(o);
    
            o = new Order("300");
            o.addItem("Burger", 8);
            o.addItem("Fries", 5);
            orders.add(o);
        }
    }

    6. Reference

    https://en.wikipedia.org/wiki/Strategy_pattern

    https://courseprobe.com/instructors/coffee-powered-crew/

    'Modeling > DesignPattern' 카테고리의 다른 글

    Single Responsibility Principle (SRP)  (0) 2020.02.26
    State  (0) 2020.02.26
    Prototype  (0) 2020.02.26
    Facade  (0) 2020.02.24
    Observer  (0) 2020.02.24

    댓글

Designed by Tistory.