2010-01-06 33 views
13

Mẫu mã sau đây là việc triển khai mẫu Chiến lược copied from Wikipedia. câu hỏi đầy đủ của tôi sau nó ...Mô hình Chiến lược Java này có lớp Ngữ cảnh dư thừa không?

main phương pháp của Wiki:

//StrategyExample test application 

class StrategyExample { 

    public static void main(String[] args) { 

     Context context; 

     // Three contexts following different strategies 
     context = new Context(new ConcreteStrategyAdd()); 
     int resultA = context.executeStrategy(3,4); 

     context = new Context(new ConcreteStrategySubtract()); 
     int resultB = context.executeStrategy(3,4); 

     context = new Context(new ConcreteStrategyMultiply()); 
     int resultC = context.executeStrategy(3,4); 

    } 

} 

Các mô hình mảnh:

// The classes that implement a concrete strategy should implement this 

// The context class uses this to call the concrete strategy 
interface Strategy { 

    int execute(int a, int b); 

} 

// Implements the algorithm using the strategy interface 
class ConcreteStrategyAdd implements Strategy { 

    public int execute(int a, int b) { 
     System.out.println("Called ConcreteStrategyA's execute()"); 
     return a + b; // Do an addition with a and b 
    } 

} 

class ConcreteStrategySubtract implements Strategy { 

    public int execute(int a, int b) { 
     System.out.println("Called ConcreteStrategyB's execute()"); 
     return a - b; // Do a subtraction with a and b 
    } 

} 

class ConcreteStrategyMultiply implements Strategy { 

    public int execute(int a, int b) { 
     System.out.println("Called ConcreteStrategyC's execute()"); 
     return a * b; // Do a multiplication with a and b 
    } 

} 

// Configured with a ConcreteStrategy object and maintains a reference to a Strategy object 
class Context { 

    private Strategy strategy; 

    // Constructor 
    public Context(Strategy strategy) { 
     this.strategy = strategy; 
    } 

    public int executeStrategy(int a, int b) { 
     return strategy.execute(a, b); 
    } 

} 

Xét đặc biệt ví dụ trên, là lớp Context dư thừa?

Ví dụ: tôi có thể đưa ra cách thực hiện thay thế sau main bằng cách sử dụng các lớp và giao diện hiện có ngoại trừ Ngữ cảnh và nó sẽ hoạt động giống hệt nhau. Nó vẫn còn lỏng lẻo.

((Chỉnh sửa: Trong kịch bản đơn giản này, khi tôi bỏ qua lớp Context, sẽ tôi được thực hiện một sai lầm tương lai))

public static void main(String[] args) { 

    IStrategy strategy; 

    // Three strategies 
    strategy = new ConcreteStrategyAdd(); 
    int resultA = strategy.executeStrategy(3,4); 

    strategy = new ConcreteStrategySubtract(); 
    int resultB = strategy.executeStrategy(3,4); 

    strategy = new ConcreteStrategyMultiply(); 
    int resultC = strategy.executeStrategy(3,4); 

} 

Tóm tắt Cập nhật

Danh sách dưới dạng điểm được phát hiện qua câu trả lời và nhận xét:

  • Bối cảnh cho phép thay đổi về cách sử dụng Chiến lược tổng hợp (ví dụ: thời gian của cuộc gọi của nó). Các bối cảnh khác nhau có thể làm các công việc nội bộ khác nhau trước và sau khi gọi Chiến lược đã cho.
  • Ngữ cảnh là "hộp đen" cấp cao. Logic bối cảnh có thể thay đổi, cũng là Chiến lược tổng hợp có thể thay đổi (hoặc một chiến lược khác được sử dụng) mà không làm hỏng máy khách vì máy khách chỉ hiểu cách gọi ngữ cảnh.
  • Mặc dù tôi đã tạo một triển khai thay thế mã mẫu Wikipedia bằng cách bỏ ngữ cảnh, và mặc dù nó hoạt động giống như bản gốc, toàn bộ tình huống đã được đơn giản hóa (trong cả hai trường hợp) và thay đổi của tôi thực sự có nghĩa là: không phải là một mẫu Chiến lược nữa, 2. Tôi nhớ những lợi ích của tinh thần của mô hình Chiến lược được đề cập ở đây.
  • Triển khai thay thế của tôi đã sử dụng phương pháp chính như Ngữ cảnh, vì vậy tôi cũng có thể giữ ngữ cảnh nếu mô phỏng hiệu quả nó. Bằng cách tạo ra một mẫu Chiến lược không tinh khiết, sự nhầm lẫn đã được tạo ra. Tôi không cần phải tái tạo lại bánh xe hoặc cố gắng thông minh hơn (trong trường hợp này).

Nếu bất kỳ điểm nào khác hữu ích hoặc nếu điều này cần chỉnh sửa để lại nhận xét và tôi sẽ sửa đổi danh sách tương ứng.

Trả lời

15

Như tên cho thấy, các Context là những gì đóng gói điểm mà tại đó chiến lược được thực hiện. Nếu không có điều đó, bạn chỉ có một số Strategy trần truồng và lớp gọi hiện nay sẽ nhận thêm trách nhiệm: biết khi nào cần tự gọi chính mình là Strategy. Ví dụ của bạn có lẽ hơi quá đơn giản, và trong trường hợp cụ thể này, tôi sẽ nói rằng Context không nhận được quá nhiều.

Một ví dụ rằng có lẽ tốt hơn cho thấy tính hữu ích của một Context là hơn như sau:

public class LoadingDock { // Context. 
    private LoadStrategy ls; // Strategy. 

    public void setLoadStrategy(LoadStrategy ls) { ... } 

    // Clients of LoadingDock use this method to do the relevant work, rather 
    // than taking the responsibility of invoking the Strategy themselves. 
    public void shipItems(List<ShippingItem> l) { 
    // verify each item is properly packaged  \ 
    // ...          | This code is complex and shouldn't be 
    // verify all addresses are correct   | subsumed into consumers of LoadingDock. 
    // ...          | Using a Context here is a win because 
    // load containers onto available vehicle  | now clients don't need to know how a 
    Vehicle v = VehiclePool.fetch();  // | LoadingDock works or when to use a 
    ls.load(v, l);       // / LoadStrategy. 
    } 
} 

Thông báo như thế nào Strategy sẽ không bao giờ được gọi trực tiếp từ một ứng dụng bên ngoài. Chỉ shipItems sử dụng chiến lược và chi tiết của các bước sau đây là hộp đen. Điều này cho phép Context điều chỉnh cách sử dụng chiến lược mà không ảnh hưởng đến khách hàng. Ví dụ, các bước có thể được sắp xếp lại hoàn toàn hoặc điều chỉnh (hoặc loại bỏ hoàn toàn) để đáp ứng các mục tiêu hiệu suất hoặc các mục tiêu khác - nhưng đối với khách hàng, giao diện bên ngoài của shipItems() trông giống hệt nhau.

Lưu ý, ngoài ra, ví dụ của chúng tôi Context, LoadingDock, có thể thay đổi LoadStrategy bất kỳ lúc nào dựa trên trạng thái nội bộ của nó. Ví dụ, nếu bến tàu quá đầy đủ, nó sẽ chuyển sang một cơ chế lập kế hoạch tích cực hơn, đẩy thùng ra và vào xe tải nhanh hơn, hy sinh một số hiệu quả khi làm như vậy (có thể xe tải không được tải hiệu quả như họ có thể đã được).

+1

Đây là một lời giải thích chi tiết kỹ lưỡng nêu rõ tầm quan trọng của bối cảnh, bao gồm cả mẫu mã hỗ trợ. Tuyệt quá. –

+0

Tôi cho rằng thêm một lớp Ngữ cảnh có thể được phân lớp để gắn thêm hành vi vào công việc ngữ cảnh cơ sở (tức là gọi lại xử lý ngữ cảnh cơ sở trước khi thực hiện công việc bổ sung). Điều tương tự cũng có thể được thực hiện với bất kỳ chiến lược cụ thể nào. Điều này sẽ cho phép các phần thay đổi hành vi độc lập với nhau nhưng vẫn tương thích với các kiểu cơ sở. Vì vậy, tôi bắt đầu nhận ra có rất nhiều tính linh hoạt cả theo chiều ngang thông qua việc triển khai thay thế và theo chiều dọc thông qua kế thừa, cũng là sự kết hợp của những thứ đó. Hấp dẫn. Mọi thứ cũng có thể phức tạp nhanh nếu không nghĩ ra. –

+0

Hmm. Tôi không chắc chắn tôi thích ý tưởng của một 'Đa ngữ' đa hình. IMO, sẽ tốt hơn khi soạn các phần khác nhau thành một 'Ngữ cảnh 'mạch lạc duy nhất, và sau đó có các chiến lược thích hợp cho mỗi trường hợp có thể áp dụng. –

3

Nó có thể là ví dụ được tạo nên này, nhưng sau đó tôi sẽ không gọi đây là ne cộng cực của Chiến lược.

Lớp Ngữ cảnh minh họa cách bạn có thể đưa ra một hành vi khác biệt của lớp đơn giản bằng cách chuyển sang một triển khai cụ thể mới của giao diện. Vì lớp chỉ biết giao diện nên không có gì thay đổi. Đó là điểm. Đừng lấy phần còn lại của ví dụ quá theo nghĩa đen.

Cách bạn mã hóa nó sẽ hoạt động, nhưng vấn đề là bạn đã bỏ điều này vào một phương pháp chính. Đó sẽ không phải là cách bạn thường sử dụng Chiến lược.Bạn sẽ làm điều đó trong một lớp, và Ngữ cảnh là một ví dụ đơn giản về điều đó.

+0

Tôi hiểu ý của bạn là gì. Tôi đã thay thế một phương pháp chính cho lớp Ngữ cảnh, điều này đặt ra câu hỏi tại sao không chỉ sử dụng một lớp Ngữ cảnh như mô hình Chiến lược xác định, để trừu tượng hóa cách sử dụng chiến lược như bạn đã mô tả. Điều này rất hữu ích với tôi vì tôi có thể nghĩ về nó từ quan điểm của những gì tôi muốn đưa vào phương pháp chính để "đơn giản hóa" mọi thứ (ví dụ như họ hơi sai) và nhận ra đó là thứ tôi có thể đặt trong ngữ cảnh. Cảm ơn. –

+0

'Tôi đã thêm phần Cập nhật Tóm tắt bên dưới câu hỏi gốc để củng cố kết quả tìm kiếm.' –

4

Đây là ví dụ tốt về cách thức thực lớp "Context" có thể nhìn vào kịch bản này:

class Accumulator { 
    private Strategy strategy; 

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

    public int accumulate(List<Integer> values) { 
     int result = values.get(0); 
     for (int i = 1; i < values.size(); i++) { 
      result = strategy.execute(result, values.get(i)); 
     } 
     return result; 
    } 
} 

EDIT: Typo trong constructor cố định

+0

Tôi thấy đúng, tên lớp là" Accumulator "và tên hàm tạo là" Context "? Tôi đến từ thế giới C# vì vậy có lẽ tôi đang nhầm một điều gì đó ở đây và thiếu điểm của bạn. –

+1

Có vẻ như hàm tạo có lỗi đánh máy. –

0

Context sẽ không dư thừa trong Strategy mẫu và nó rất hữu ích trong các tình huống dưới đây:

  1. Mã để gọi một đặc biệt Strategy đang lây lan trong nhiều lớp mà không gọi Context. Trong tương lai, nếu bạn phải tái yếu tố hoặc thay đổi giao diện Strategy, nó sẽ trở thành một nhiệm vụ bận rộn.
  2. Giả sử rằng một số dữ liệu cần được điền trước khi gọi một Chiến lược cụ thể. Bối cảnh phù hợp nhất ở đây bằng cách cung cấp thông tin bổ sung và gọi phương thức Chiến lược của một Chiến lược cụ thể.

    ví dụ: Context sẽ nhận được tham số Chiến lược và userId. Trước khi thực hiện Strategy, Context cần cung cấp nhiều thông tin bổ sung liên quan đến Hồ sơ người dùng. Context sẽ tìm nạp thông tin bắt buộc và thực thi phương pháp chiến lược. Trong trường hợp không có bối cảnh, bạn phải sao chép mã tại 100 địa điểm khác nhau nếu bạn gọi phương pháp chiến lược ở 100 địa điểm khác nhau.

  3. Context có thể đưa ra quyết định độc lập về Chiến lược cần thực hiện. Nó có thể đơn giản thay đổi loại chiến lược tùy thuộc vào cấu hình thời gian chạy. Chiến lược cốt lõi USP là chuyển đổi giữa gia đình của thuật toán liên quan. Bối cảnh là nơi tốt nhất để đạt được nó.

  4. Nếu bạn phải hành động theo nhiều Chiến lược, Context là nơi tốt nhất.Câu trả lời được đề xuất của axtavt sử dụng Accumulator là một ví dụ.

Tham khảo bài đăng này để biết thêm chi tiết.

Real World Example of the Strategy Pattern

Các vấn đề liên quan