2013-08-14 31 views
11

Tôi đang cố gắng hiểu mô hình nhà máy. Nếu có nhiều triển khai thì mẫu nhà máy của tôi sẽ có nhiều trường hợp khác hoặc chuyển đổi. Và cũng mỗi khi tôi giới thiệu một triển khai mới, tôi nên thay đổi mã nhà máy của mìnhmô hình nhà máy cách tiếp cận năng động

Giống như trong ví dụ bên dưới nếu cho phép vịt con đang triển khai giao diện thú cưng như ngày mai nếu nhiều động vật triển khai giao diện thú cưng của tôi. nếu mã hoặc trường hợp chuyển đổi. Có cách nào để giải quyết vấn đề này với cách tiếp cận năng động hơn không?

package com.javapapers.sample.designpattern.factorymethod; 

//Factory method pattern implementation that instantiates objects based on logic 
public class PetFactory { 

    public Pet getPet(String petType) { 
     Pet pet = null; 

     // based on logic factory instantiates an object 
     if ("bark".equals(petType)) 
      pet = new Dog(); 
     else if ("quack".equals(petType)) 
      pet = new Duck(); 
     return pet; 
    } 

Nếu động vật phát triển

if ("bark".equals(petType)) 
    pet = new Dog(); 
else if ("quack".equals(petType)) 
    pet = new Duck(); 
else if ("mno".equals(petType)) 
    pet = new MNO(); 
else if ("jkl".equals(petType)) 
    pet = new JKL(); 
else if ("ghi".equals(petType)) 
    pet = new GHI(); 
else if ("def".equals(petType)) 
    pet = new DEF(); 
...... 
else if ("abc".equals(petType)) 
    pet = new ABC(); 
return pet 
+0

Vâng, không có gì để làm. Nhà máy xây dựng của nó –

Trả lời

20

Tôi nghĩ rằng có một cách tiếp cận năng động:

  1. Trong nhà máy của bạn, bạn cần một Map<String, Class<? extends Pet>>
  2. Trong constructor tĩnh của mỗi lớp, kéo dài Pet, đăng ký nó với bản đồ như vậy.
  3. Thần tạo ra một lớp sẽ chỉ map.get(pet).newInstance (bạn phải kiểm tra null, tất nhiên)
+0

+1 để thực sự nhận được điểm của một nhà máy lớp học. –

+5

Tuy nhiên, trước tiên, hãy lưu ý rằng lớp phải được tải cho hàm dựng tĩnh của nó để được thực hiện. Điều này không xảy ra tự động nếu lớp không bao giờ được tham chiếu. Nếu bạn đã từng chạy vào một API, nơi bạn đã phải làm một cái gì đó tùy ý 'Class.forName (" ")' một cái gì đó đầu tiên, đó là một cuộc biểu tình này. Đây không phải là điều cấm kỵ, nó chỉ là một cái gì đó cần lưu ý; một cái gì đó ở đâu đó sẽ phải tải các lớp. –

+0

bạn có thể vui lòng chỉ một số ví dụ. – dataEnthusiast

9

Ý tưởng đằng sau mô hình nhà máy là để cho bạn tự động nhanh chóng đối tượng mà loại bạn không nhất thiết phải biết về lúc thiết kế.

Có một khối lớn if đánh bại mục đích đó. Cách hiệu quả để thực hiện mẫu này là cũng có một nhà máy cho từng loại, thực hiện một giao diện nhà máy cơ sở và có khả năng khởi tạo một đối tượng mới của loại đó (bằng cách này, trong Java, được xây dựng- trong Class là một ví dụ về một nhà máy như vậy).

Sau đó, bạn đăng ký bản đồ tên/id/v.v. cho các trường hợp của các nhà máy riêng lẻ này trong thời gian chạy. Khi đó là thời gian để khởi tạo một trong các loại, bạn tìm kiếm nhà máy trên bản đồ theo tên và sử dụng nó để khởi tạo một đối tượng mới thuộc loại đó.

Cách bạn đăng ký từng nhà máy trên bản đồ hoàn toàn trong không khí. Bạn có thể đăng ký một số rõ ràng, bạn có thể quét tệp cấu hình, v.v.

Thực chất bạn muốn thay thế khối if bằng bản đồ được tạo động khi chạy.

Bạn thậm chí không cần phải chỉ sử dụng một "bản đồ" đã được đăng ký trước - đôi khi có thể thích hợp để tìm ra cách tạo đối tượng với tên được cung cấp hoặc kết hợp cả hai (ví dụ: Class.forName() tìm kiếm đường dẫn lớp nếu nó không thể tìm thấy lớp đã được nạp). Vấn đề là việc dịch tên thành loại lớp có thể xảy ra mà không có nhà máy cơ sở thực sự biết loại lớp là gì. Cần chú ý rằng sự phản chiếu Java cung cấp khả năng thực thi nhà máy rất khả thi đã qua Class.forName() và/hoặc Class.newInstance(), vì vậy hãy cân nhắc việc sử dụng thay vì phát minh lại bánh xe nếu nó có ý nghĩa.

+4

Chỉ để thêm tên, mẫu này được gọi là 'Mô hình nhà máy trừu tượng'. –

2

phản ánh sử dụng

public Pet getPet(String petType) 
{ 
    Pet _pet = (Pet)Class.forName(petType).newInstance(); 
    return _pet; 
} 

bạn cần phải thay đổi lập luận của bạn khỏi 'vỏ', 'quack' thành 'Dog' và 'Duck', v.v.

1

Tôi đã đập đầu vào vấn đề này vì tôi gặp vấn đề tương tự, và cuối cùng tôi đi kèm với giải pháp dựa trên Reflections Library (chú ý đến trận chung kết S trong Reflections!)

Nó có thể được áp dụng cho vấn đề của bạn NẾU tất cả các lớp con thú cưng của bạn có một thuộc tính có thể được sử dụng để phân biệt chúng, ví dụ

public String petType; 

Phương pháp của nhà máy của bạn có thể như sau:

 public static Pet getPet(String _petType) { 
    String packageName = "your.package.with.pet.classes"; 

    Reflections reflections = new Reflections(packageName); 

    Set<Class<? extends Pet>> allPets = reflections 
      .getSubTypesOf(Pet.class); 

    Iterator<Class<? extends Pet>> it = allPets.iterator(); 

    while (it.hasNext()) { 
     try { 
      Pet pet = it.next().newInstance(); 
      if (pet.petType.equals(_petType)) 
       return pet; 
     } catch (InstantiationException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IllegalAccessException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

    System.out.println("Pet " + _petType 
      + " not yet implemented in package " + packageName); 
    return null; 
} 

Phương pháp này sẽ không bị ảnh hưởng nếu Vật nuôi mới được xác định.

Ưu điểm:

  • Nó không cần phải sửa đổi hơn nữa để lớp con thú nuôi, không phải bất kỳ loại khởi tạo/đăng ký trên một cấu trúc đồ duy trì bởi Nhà máy

  • Đó là tổng quát hơn các giải pháp dựa trên API phản chiếu Java vì bạn có thể phân biệt các lớp con Pet khi một số thuộc tính thay vì tên lớp

Nhược điểm:

  • Nó tạo ra các phiên bản cục bộ của tất cả các lớp con Thú cưng để tìm lớp thích hợp. Về phía này, tôi tin rằng cách tiếp cận này có thể được cải thiện.
Các vấn đề liên quan