2012-12-06 30 views
5

Chúng tôi có nhiều DAO trong một dự án hiện có (hiện tại không có giao diện, nhưng điều đó có thể thay đổi). Thay vì hệ thống dây điện một Spring bean được quản lý cho mỗi lớp DAO và tiêm chúng vào các lớp dịch vụ, chúng tôi có một DAO "nhà máy" của các loại trông như thế này:Chiến lược cho nhiều DAO trong Spring Java

public class DAOFactory { 
private static DAOFactory daoFac; 

static{ 
    daoFac = new DAOFactory(); 
} 

private DAOFactory(){} 

public static DAOFactory getInstance(){ 
    return daoFac; 
} 

public MyDAO1 getMyDAO1(){ 
    return new MyDAO1(); 
} 

    public MyDAO2 getMyDAO2(){ 
    return new MyDAO2(); 
} 
    ... 

(Lưu ý rằng MyDAO1 và MyDAO2 là lớp bê tông)

Điều này cho phép chúng tôi dễ dàng thêm/gọi các phương thức DAO trong lớp Dịch vụ, mà không cần phải 1.) thêm giao diện DAO làm thuộc tính cho lớp dịch vụ 2.) triển khai DAO vào phương thức dịch vụ thông qua cấu hình. (Và đôi khi chúng tôi sử dụng nhiều DAO trong một lớp dịch vụ).

DAOFactory.getInstance().getMyDAO1().doSomething(); 

Chiến lược này đã có hiệu quả cho chúng tôi, nhưng tôi tự hỏi liệu có cách nào tốt hơn nếu chúng tôi có thể bắt đầu mới không? Tôi nhìn autowiring DAO như đậu, nhưng tôi vẫn cần phải tạo thuộc tính trong mỗi lớp dịch vụ để đại diện cho những DAO đang được sử dụng. Và trong một dự án lớn, tôi đang do dự để bắt đầu tự động dây đậu anyway - chúng ta cần phải cung cấp khả năng hiển thị cho tất cả các nhà phát triển.

Tôi cảm thấy như tôi đang lật-thả giữa một.) Được kết hợp chặt chẽ với việc triển khai, nhưng ít chi phí mã/cấu hình và b.) Được kết nối lỏng lẻo với giao diện, nhưng đòi hỏi nhiều chi phí mã/cấu hình.

Có cách nào tốt hơn tôi bị thiếu không? Một cái gì đó ở giữa? Ý kiến ​​được hoan nghênh.

+3

Tại sao bạn sử dụng Spring nếu bạn không như tiêm phụ thuộc? Chỉ cần autowire các DAO trong các lớp dịch vụ: đó là những gì Sring và DI là tất cả về. Sau đó viết một bài kiểm tra đơn vị cho dịch vụ của bạn bằng cách tiêm một DAO giả và xem xét việc thử nghiệm nó dễ dàng hơn bao nhiêu so với một nhà máy tĩnh. –

+2

Chúng tôi có một lớp học tương tự như lớp bạn đang cố gắng ở đây, nhưng như JB Nizet đề cập, chúng tôi @Autowired DAOs vào nó. Một điều quan trọng về autowiring DAOs là Spring quản lý chúng tại Singletons theo mặc định, vì vậy bạn sẽ không nhận được rất nhiều sáng tạo đối tượng. Ví dụ mã của bạn tạo ra một bản sao mới của mỗi DAO mỗi khi bạn cần sử dụng một DAO nhất định, và sẽ không cần thiết cho điều đó. – Marvo

+0

@JB Nizet: Chúng tôi sử dụng DI nhiều, không chỉ cho DAO. Tôi không nghĩ ra phương pháp này, nhưng tôi có cơ hội để làm lại nó, do đó câu hỏi. –

Trả lời

5

Tôi sẽ có tất cả các DAO như các thành phần được quản lý trong mùa xuân và đưa chúng vào các dịch vụ cho khớp nối lỏng lẻo. Tại sao bạn nghĩ rằng đậu autowiring là xấu trong một dự án lớn.?

Chỉ cần chú thích mỗi lớp DAO với @Component và thay thế MyDao mydao = factory.getmyDao() với

@Autowired MyDao myDao;

Tôi không thấy nhiều overhead mã hóa/cấu hình với nó.

0

Nếu bạn sử dụng quá nhiều DAO trong 1 dịch vụ mà bạn nên suy nghĩ về chia 1 dịch vụ thành đòn bẩy thấp hơn (tốt hạt) Dịch vụ

1

Tốt câu hỏi.

Tôi nghĩ điều đó thật đáng tiếc khi bạn bắt đầu sử dụng DAOFactory. Mùa xuân là một nhà máy siêu linh hoạt, vì vậy tôi thực sự không hiểu tại sao bạn cần một cái khác. Autowiring trong mùa xuân có rất nhiều lợi thế và không reqire giao diện, vì vậy bạn có thể dễ dàng chuyển sang sử dụng mùa xuân để truy cập DAO. IMHO nó không giảm nhưng cải thiện khả năng hiển thị cho các nhà phát triển khác.

Hơn nữa nếu bạn đang nghĩ về refactoring của lớp DAO hãy xem trên GenericDAO từ google mã: http://code.google.com/p/hibernate-generic-dao/

Tôi đã có một kinh nghiệm rất tốt với thư viện này. Nó tiết kiệm thời gian của bạn. Bạn thực sự không cần nhiều DAO. Bạn cần chính xác một DAO. Bạn rõ ràng có thể bọc DAO chung từ mã google và thêm thuật ngữ và chức năng ứng dụng cụ thể của bạn. Nhưng không thêm mã thực thể cụ thể ở đó. Mã thực thể cụ thể phải ở lớp dịch vụ. Không có HQL dễ vỡ hơn, không có sự kết hợp với hibernate nếu bạn đang sử dụng API tiêu chuẩn Hibernate. Thư viện này hỗ trợ cả Hibernate và JPA và API của nó rất đơn giản và mạnh mẽ.

3

Tôi đã thực hiện một vài cách tiếp cận khác nhau cho đến nay với các dự án của mình và chưa thực sự giải quyết được những gì là "tốt nhất". Và có thể không phải là "tốt nhất" nhưng có lẽ là "tốt nhất cho nhu cầu của bạn".

Trước tiên, tôi đã đi với một lớp dịch vụ cơ sở.

public abstract BaseService { 
    @Autowired FooDAO fooDao; 
    @Autowired BarDAO barDao; 
    . . . 
    . . . 
    protected getFooDAO() { 
     return this.fooDao; 
    } 
} 

Sau đó, trong các lớp dịch vụ của tôi, tôi có thể viết đơn giản

Foo foo = getFooDAO().uniqueById(id); 

này hoạt động, và nó giữ dịch vụ của tôi gọn gàng từ tất cả các autowiring và accessor lớp dành cho các biến dụ dao. Vấn đề là, bây giờ tôi đã có một bản sao của lớp cơ sở này trong mỗi dịch vụ của tôi, mà thẳng thắn, meh, không phải là một vấn đề lớn. Nhưng nó cũng tạo ra một mùi mã bởi vì nó không sử dụng thành phần trên thừa kế, trong thực chất, một lý do cho DI là khuyến khích thành phần.

Một đồng nghiệp đề xuất một nhà máy như nhà máy của bạn và gọi nó là ServiceProvider. Chúng tôi autowire này vào dịch vụ của chúng tôi.

@Component 
public class ServiceProvider { 
    @Autowired FooDAO fooDao; 
    public FooDAO getFooDAO() { 
     return this.fooDao; 
    } 
    . . . 
    // yadda yadda 
} 

Sau đó, chúng tôi có một cái gì đó giống như những gì bạn có:

Foo foo = getServiceProvider().getFooDAO().uniqueById(id); 

Và đó là khá darned xấu xí và thực sự không thích hợp để rõ ràng. Vì vậy, chúng tôi đã dabbled với việc sử dụng chỉ là trường hợp của nhà cung cấp, và đặt tên cho nó một cái gì đó ngắn và ngọt ngào như sp. Sau đó, chúng tôi nhận được

Foo foo = this.sp.getFooDAO().uniqueById(id); 

Và một lần nữa, nó hoạt động. Và nó có lẽ là một thiết kế tốt hơn. Và chúng tôi chỉ tự động sửa đổi các DAO ở một nơi, chứ không phải vào mỗi Dịch vụ, mặc dù đó không thực sự là vấn đề lớn. Nhưng nó làm cho tôi cảm thấy tốt hơn mặc dù Tôi cảm thấy tốt hơn không phải là một yêu cầu dự án (nhưng không cha nghĩ rằng nó là?)

Tôi đã nghĩ chúng tôi sẽ kết hợp cả hai. Chúng ta sẽ thay đổi BaseService để autowire ServiceProvider, và sau đó bọc các cuộc gọi xấu xí.

public abstract BaseService { 
    @Autowired ServiceProvider serviceProvider; 

    protected getFooDAO() { 
     return this.serviceProvider.getFooDAO(); 
    } 

    protected getBarDAO() { 
     return this.serviceProvider.getBarDAO(); 
    } 
} 

Làm cho tốc ký đẹp hơn trong dịch vụ của tôi, không yêu cầu tôi để autowire mỗi DAO vào mỗi dịch vụ mà chỉ được clunky, theo ý kiến ​​của tôi, nhưng cũng không có một bản sao của tất cả những tài liệu tham khảo trong mỗi dịch vụ mà bạn biết, là một mối quan tâm hoàn toàn vô lý.

Sự cố mà tôi bỏ qua là bước qua mã trong trình gỡ lỗi. Bước vào và ra khỏi mỗi cuộc gọi getWhateverDAO() là tẻ nhạt, và thêm một bước có thể thông qua getServiceProvider() cũng không giúp ích gì cả.

Nhưng đó là nơi tôi gặp vấn đề này. Thành thật mà nói, tôi nghĩ rằng tôi dành rất nhiều thời gian suy nghĩ về điều này bởi vì nó là một cách tuyệt vời để tránh tất cả các vấn đề thực sự khó khăn ứng dụng của chúng tôi đặt ra.

0

Nếu bạn không muốn chú thích các lớp DAO của bạn hoặc có chú thích cấu hình như @Value gây ô nhiễm cho họ, tôi thấy hai lựa chọn:

1.Tạo một @Configuration với DAO @Bean s

@Configuration 
public class DaoConfiguration { 

    @Value("${db.name}") 
    private String dbName; 

    @Value("${foo.table}") 
    private String fooTable; 

    @Value("${bar.table}") 
    private String barTable; 

    @Bean 
    private FooDao fooDao() { 
     return new FooDao(dbName, fooTable); 
    } 

    @Bean 
    private BarDao barDao() { 
     return new BarDao(dbName, barTable); 
    } 
} 

Sau đó tạo một trường @Autowired cho DAO bạn cần:

@Autowired 
private FooDao fooDao; 

2. Tạo một nhà máy DAO @Component

hữu ích nếu bạn cần để làm một số dọn dẹp khi DAO bị phá hủy.

@Component 
public class DaoFactory { 

    @Value("${db.name}") 
    private String dbName; 

    @Value("${foo.table}") 
    private String fooTable; 

    @Value("${bar.table}") 
    private String barTable; 

    private FooDao fooDao; 
    private BarDao barDao; 

    @PostConstruct 
    public void init() { 
     fooDao = new FooDao(dbName, fooTable); 
     barDao = new BarDao(dbName, barTable); 
    } 

    @PreDestroy 
    public void destroy() { 
     try { 
      fooDao.close(); 
     } catch (Exception e) { 
      log.error("Failed to clean up FooDao", e); 
     } 
     try { 
      barDao.close(); 
     } catch (Exception e) { 
      log.error("Failed to clean up BarDao", e); 
     } 
    } 

    public FooDao fooDao() { 
     return fooDao; 
    } 

    public BarDao barDao() { 
     return barDao; 
    } 
} 

Sau đó tạo một trường @Autowired cho nhà máy ở các lớp học bạn cần DAO:

@Autowired 
private DaoFactory daoFactory; 

Và sử dụng nó như:

daoFactory.barDao().findAll(); 
Các vấn đề liên quan