Dependency Injection với Abstract Factory


Bài viết này, chúng ta cùng tìm hiểu ưu và nhược điểm của Dependency Injection (DI - “tiêm ” phụ thuộc) với một số cách khác nhau dùng Abstract Factory design pattern. Đặt trong ngữ cảnh của một số vấn đề như: Tạo stateful objects với tham số, điều khiển kiểm tra exceptions khi tạo object, và gắn động các objects. Mà các IoC frameworks, như Spring IoC container, PicoContainer và Guice, không đưa ra giải pháp tốt nhất cho các trường hợp này.

Abstract Factory Design Pattern cho Dependency Injection


GoF* Abstract Factory design pattern được tóm gọn theo 2 bước:
Một factory interface thay thế cho một class abstract factory (Optional),
Mọi factory method chịu trách nhiệm tạo một object và tiêm phụ thuộc vào nó.
Xét ví dụ đơn giản sau:

ComponentA phụ thuộc vào ComponentB. Để có thể unit-testing class ComponentAImpl, hiện thực của interface ComponentB phải tiêm vào ComponentAImpl. Đoạn code sau minh hoạ cách dùng Abstract Factory design pattern để tiêm phụ thuộc.

//Abstract Factory for Dependency Injection
//Factory interface
public interface Module1ServiceFactory {

ComponentA getComponentA();

ComponentB getComponentB();
}

//Concrete factory
public class Module1ServiceFactoryImpl implements Module1ServiceFactory {

private ComponentA componentA;
private ComponentB componentB;
private Module1Servicefactory instance;

private Module1ServicefactoryImpl() {
}

public static synchronized Module1ServiceFactory getInstance() {
if (null == instance) {
instance = new Module1ServicefactoryImpl();
componentA = new ComponentAImpl();
componentB = new ComponentBImpl();
componentA.setComponentB(componentB);
}
return instance;
}

public ComponentA getComponentA() {
return componentA;
}

public ComponentB getComponentB() {
return componentB;
}
}

//Client
public class Client {

public static void main(String[] args) {
Module1ServiceFactory m1sf =
Module1ServicefactoryImpl.getInstance();
ComponentA componentA = m1sf.getComponentA();
componentA.operationA1();
}
}


Lazy-instantiation


Lazy-instantiation có thể thực hiện bàng cách thay đổi phương thức để có thể xem như objects đã được tạo và chỉ lấy ra khi cần. Để làm điều này, getComponentA() có thể chỉnh lại như sau:

public synchronized ComponentA getComponentA() { if (null == componentA) { componentA = new ComponentAImpl(); } return componentA; }

Dĩ nhiên Module1ServiceFactoryImpl.getInstance() phải được sửa lại không tạo objects.
Ta có thể thêm parameter cho Module1ServiceFactoryImpl .getInstance() để cho biết nó có cần tạo objects hay không.

Non-Singleton Scope


Đoạn code trên sẽ tạo singleton objects. Nếu một object mới chỉ cần khi gọi phương thức getComponentA() và getComponentB(), thì ta sửa lại như sau:


//Concrete factory
public class Module1ServiceFactoryImpl {
private Module1ServiceFactory instance;

private Module1ServiceFactoryImpl() {}

public static synchronized Module1ServiceFactory getInstance() {
if (null == instance) {
instance = new Module1ServiceFactoryImpl();
}

return instance;
}

public ComponentA getComponentA() {
ComponentA componentA = new ComponentAImpl();
ComponentB componentB = getComponentB();
componentA.setComponentB(componentB);
return componentA;
}


public ComponentB getComponentB() {
return new ComponentBImpl();
}
}


Ta có thể tiêm một singleton object vào một non-singleton object. Ví dụ, nếu ComponentB là một singleton, và ComponentA là một non-singleton, ta có thể làm như sau:

//Concrete factory
public class Module1ServiceFactoryImpl {
private Module1ServiceFactory instance;
private ComponentB componentB;

private Module1ServicefactoryImpl() {}

public static synchronized Module1ServiceFactory getInstance() {
if (null == instance) {
instance = new Module1ServiceFactoryImpl();
componentB = new ComponentBImpl();
}

return instance;
}

public ComponentA getComponentA() {
ComponentA componentA = new ComponentAImpl();
componentA.setComponentB(componentB);
return componentA;
}

public ComponentB getComponentB() {
return componentB;
}
}

Ngược lại ta cũng có thể tiêm một non-singleton object cho một singleton, tuy nhiên trường hợp này rất ít gặp.

Tạo Local Stateful Objects với tham số cho Singletons


Đây là vấn đề đặt trưng cho tất cả các IoC frameworks. Được minh hoạ bằng phương thức cho ComponentA singleton:

public void operationA2() {
String s = aPrivateMethod();
int i = anotherMethod();
ComponentC componentC = new ComponentCImpl(s, i);
//do something else.
}

Ở đây, ComponentAImpl dùng ComponentC. Hiển nhiên là chúng ta cần tiêm cho nó một hiện thực của ComponentC là ComponentCImpl. Tuy nhiên, chúng ta không thể tạo biến componentC khi nó là một stateful object với trạng thái chỉ dùng được trên client và sẽ không thể dùng trong clients khác thông qua threads. Vậy, nó không thể tiêm dùng setter hay constructor.
Có 2 giải pháp để giải quyết vấn đề này dùng Abstract Factory pattern. In both schemes, chúng ta cần thay đổi Module1ServiceFactory và thêm một tham số cho factory method:

ComponentC getComponentC(String s, int i);

Và hiện thực phương thức này trong Module1ServiceFactoryImpl:

public ComponentC getComponentC(String s, int i) {
return new ComponentCImpl(s, i);
}

Giải pháp thứ nhất là tiêm factory object vào class có local stateful objects cần:

private Module1ServiceFactory factory;
public void setModule1ServiceFactory(Module1ServiceFactory factory) {
this.factory = factory;
}

ComponentAImpl.operationA2() trở thành:

public void operationA2() {
String s = aPrivateMethod();
int i = anotherMethod();
ComponentC componentC = factory.getComponentC(s, i);
//do something else.
}

Bất lợi của cách này là ComponentAImpl phụ thuộc vào Module1ServiceFactory và chúng ta cần cung cấp một mock hiện thực Module1ServiceFactory để unit-test ComponentAImpl. Mặc dù có nhược điểm như vậy, nhưng tiêm factory object vào một class dùng trong việc tạo local stateful objects là đơn giản nhất. Và được dùng nhiều nhất trong J2EE technology. Ví dụ, trong JPA (Java Persistence API), một entity manager factory có thể tiêm vào code, và một application-managed entity manager được tạo từ entity manager factory.
Cách thứ 2 để tạo local stateful objects là chuyển phương thức sang abstract class, có thể dùng trong unit-tested, và có objects phụ thuộc cụ thể trong subclass.

public abstract class AbstractComponentA implements ComponentA {
public void operationA2() {
String s = aPrivateMethod();
int i = anotherMethod();
ComponentC componentC = getComponentC(s, i);
//do something else.
}

public abstract ComponentC getComponentC(String s, int i) ;

}

public class ComponentAImpl extends AbstractComponentA {
public ComponentC getComponentC(String s, int i) {
return new ComponentCimpl(s, i);
}

}

Cách này được dùng nhiều trong Method Injection của Springframework chỉ hỗ trợ trường hợp không cần tham số khi tạo stateful objects. Unit-testing code không cần hiện thực mock factory. Tuy nhiên, đó là một giải pháp nguy hiểm. Giả sử chúng ta có 10 local stateful objects trong, chúng ta cần 10 abstract methods cho mục đích dùng unit-testing. Đúng là có thể dùng unit-testing và dùng rất đơn giản – at the expense of cluttered application code.
Springframework đưa ra phương thức có thể giải quyết vấn đề này dùng Java reflection. Nhưng nó là một cách rất phức tạp và không phù hợp cho một application bình thường.

Kiểm tra Exceptions Thrown khi tạo Object


Đây là vấn đề mà một IoC container thường làm không tốt. Nếu kiểm tra exceptions được tung ra trong quá trình tạo object, ứng dụng có thể muốn bắt và thu lại. Lấy ví dụ một web service client, nếu web service chưa được tạo khi client gọi, client có thể bắt exception mà nó tung ra, hiện messages phù hợp và đề nghị thực hiện lại. Trường hợp này khó cho IoC containers để tung ra lổi đã được khai báo trong ứng dụng. Factories có thể dể dàng điều khiển trạng thái – chúng ta có thể đơn giản khai báo exceptions cần kiểm tra và tung lổi trong factory methods và cho phép application code điều khiển và thu lại ngay tại đó.

Gắn linh động


Là trường hợp có nhiều hiện thực khác nhau của cùng một interface cần tiêm vào một object khác nhau. Một ví dụ hay là Strategy design pattern. Một tham số có thể dùng để cho biết class cụ thể nào cần được tiêm. Trường hợp này khó hiện thực theo kiểu tiêm phụ thuộc trong file XML hỗ trỡ trong IoC containers, chỉ đơn giản cung cấp một cách để lắp các objects theo cách tĩnh. Lập trình IoC containers có thể cho phép giải quyết cấn đề phụ thuộc động. Tuy nhiên, tiêm phụ thuộc bằng tay với Abstract Factory cung cấp một cách đơn giản nhất và và là một giải pháp đơn giản nhất trong trường hợp này, như ta thấy trong ví dụ sau:

//Concrete factory
public class Module1ServiceFactoryImpl {
...

public ComponentA getComponentA(int strategy) {
ComponentA componentA = new ComponentAImpl();
ComponentB componentB = getComponentB(strategy);
componentA.setComponentB(componentB);
return componentA;
}


public ComponentB getComponentB(int strategy) {
switch(strategy) {
case STRATEGYA:
return new StrategyA();
case STRATEGYB:
return new StrategyB();
default:
return null;
}
}
}

Trong ví dụ này, cả StrategyA và StrategyB đều là hiện thực của interface ComponentB.

Tổng kết


Các trường hợp đã được đưa ra cho vấn đề tiêm phụ thuộc với Abstract Factory design pattern bao gồm tạo local stateful objects từ tham số động, điều khiển kiểm tra exceptions trong quá trình tạo object, và gắn linh động. Bên cạnh đó, vấn đề là một cách tốt nhất để so sánh với các IoC containers từ dùng Java code và gắn cứng (XML). Bất lợi ở chổ developers cần viết nhiều code hơn để bắt đầu. Một hạn chế khác là hiện thực của factory code thay đổi đáng kể nếu chúng ta đổi giựã lazy-initialization và eager-initialization hay từ singletons đến non-singletons. Tuy nhiên, nó có thể chứng tỏ rằng it is rare that we need to make these kinds of changes.
Vấn đề chính là cho phép unit-testing là lập trình dùng interfaces để classes không dựa vào classes cụ thể trong ứng dụng. Để mock objects có thể tiêm vào một class khi test và thi hành tất cả sự phụ thuộc.
Phụ thuộc đã được giải quyết, theo một cách nào đó trong ứng dụng. Một ý tưởng thường thấy phía sau tất cả IoC containers và các giải pháp cho DI là phụ thuộc được giải quyết theo cách dể hình dung – XML configuration files (Spring IoC), đặc biệt Java classes (Google Guice), hay factory classes cụ thể. Trong trường hợp này, chúng ta tránh sự lan rộng của phụ thuộc thông qua code ứng dụng và một ít class cụ thể có thể dễ dàng. Mock objects có thể dùng để unit-testing.
Và cuối cùng, với IoC containers, chúng ta loại trừ phụ thuộc vào classes cụ thể và có thể tạo unit-testing, theo cách mà họ cung cấp – thông qua các thirty-party APIs hay cấu hình trên file XML. Khi không có một chuẩn cho IoC containers và mổi framework cung cấp các tính năng và chức năng khác nhau chung quanh vấn đề tiêm phụ thuộc, thì ta khó mà thay thế một IoC framework để dùng một cái khác.

*GoF: Gang of Four. Người ta thường gọi quyển sách Design Patterns: Elements of Reusable Object-Oriented Software với cái tên này vì có 4 tác giả viết nó.

Dịch từ TheServerSide

Đọc tiếp >>

Cao Trong Hien

,

10 Blogs hữu ích cho Web Developer


Làm thế nào để biết được thế giới này đang có những gì, và cần gì?

Làm sao để lựa chọn một công nghệ web cho dự án mà mình đang tiến hành?

Dùng media player nào? Flex hay Silverlight?

Dùng ngôn ngữ nào? Java, .Net hay PHP?

Và còn rất nhiều câu hỏi mà để tìm ra câu trả lời thì cần có một khoảng thời gian gắn bó, hay chỉ đơn giản là tìm kiếm trên một số websites hữu ích. Bạn chọn cách nào?

Với tôi thì vấn đề ngôn ngữ là dễ dàng, vì tôi chỉ chọn Java। Nhưng dùng frameworks nào? JSP, Servlet, Struts, JSF, Spring MVC... thì cũng khá là đau đầu.

Các blogs sau sẽ cung cấp một số kiến thức bổ ích về thế giới Internet.


1. Smashing Magazine

Smashing Magazine là một trong những nơi để tìm một mẫu thiết kế hay ít nhất là ý tưởng. Mỗi bài viết là một bìa học về thiết kế web và phát triển, và là một blog không thể thiết đối với một web designer.

2. Ajaxian

Có ai đó nói rằng: “nếu bạn biết Javascript, thì bạn đã biết 80% về Ajax”. Thì Ajaxian phần lớn các bài viết nói về Javascript, và các thư viện Javascript như Dojo hay JQuery. Cường độ post bài là 5 đến 10 mỗi ngày, thì đây là một trang đáng xem đối với các Web 2.0 Developer.

3. ReadWriteWeb

Mọi thứ diễn ra trong thế giới internet, bạn đều có thể tìm thấy trên ReadWriteWeb. Nếu bạn là một nhà kinh doanh trên internet hay xây dựng websites, thì đây là blog sẽ đem đến cho bạn một kiến thức bổ ích cho công việc. Được xây dựng một cách bài bản, với số lượng bài đều đặn, blog này đang có một thứ hạng cao với PC World’s Top 100 và Technorati’s Top 20.

4. Adam Bien’s Blog

Bài viết là những nhận xét về kỹ thuật, vấn đề mắc phải, tutorial về JavaEE và mọi thứ liên quan đế Sun. Là một địa chỉ không thể thiếu đối với những Java EE Developer.

5. Flex Examples

Flex là một framework đang được dùng khá phổ biến trong Rich Internet Application – Nói đến các ứng dụng web có tính năng và đặc tính như một ứng dụng trên máy desktop- (RIA). Đây là một framework hay, nhưng cũng có nhiều thứ khó có thể làm theo ý mình. Flex Examples sẽ giúp bạn giải quyết các vướng mắc khi sử dụng bằng các tutorials nhằm giải quyết các vấn đề. Nếu bạn là một Flex developer, bạn không thể bỏ qua blog này.

6. Vitamin

Được viết theo kiểu “how-to” tutorials chung quanh các vấn đề về thiết kế và hiện thực websites. Mỗi tutorial được trình bày một cách rỏ ràng theo một ngôn từ dễ hiểu. Họ được nhận giải SXSW Award 2007 Best Education Resource - nơi tốt nhất để học tập.

7. Agile Ajax

AJAX đang đóng một vai trò lớn trong phát triển web. Agile Ajax viết về các tutorials và các đoạn code hữu ích cho Javascript developer. Bên cạnh tutorials, họ còn có các bình luận về sách.

8. Slashdot

Đây cũng là một trong những blog chuyên về các tin tức công nghệ rất được yêu thích. Bạn cũng có thể tìm thấy những comment rất thẳng thắn và thú vị ở đây.

9. TechCrunch

Với xứ mệnh tìm kiếm các thông tin và bình luận về các công ty và sản phẩm internet. Tìm ra xu hướng và các công ty hứa hẹn đem đến một nét mới cho internet. Người sáng lập ra blog này là luật sư Michael Arrington. Những mối quan hệ của Arrington đã mang tới cho blog những tin tức mới nhất trước khi phần còn lại của thế giới biết đến.

10. A List Apart

Những bài viết mà tôi mong chờ ở họ bao gồm web-standards, best practices, accessibility, và usability. Những bài viết của ALA có chất lượng rất tốt và họ chỉ post khoảng 2 bài một tháng, nhưng cũng đáng để chờ. Được viết bởi những người có uy tín trong ngành, trong đó có Eric MeyerJeffrey Zeldman.


Hi vọng các bạn có thể học được nhiều điều từ các websites trên. Và tất nhiên, sự thiếu nếu có thêm một site nào hay thì có thể chia sẽ trong comment


Đọc tiếp >>

Cao Trong Hien

,

Hiendt's weblog – Cái nhìn mới


Cuối cùng thì cũng xong! Một giao diện mới.
Có lẽ tôi đặt tên cho nó là red steel vì nó được lấy từ template blue-steel của bloggerbuster.

Mất 4 ngày chỉnh sửa, tôi cho rằng ổn, Với một số tính năng mới:


  • Tính năng đọc thêm cho bài viết

  • Chia sẽ bài viết bằng comment hay các trang chia sẽ (Digg, StumbleUpon, và del.icio.us)

  • Tính năng cho các bài viết liên quan


Chuyển từ tông xanh sang đỏ là không dễ dàng, các bạn có thể thấy cái vẻ gượng gạo trong cách phối màu। Cái này là chắc rồi vì tôi chỉ là một developer mà.

Mọi ý kiến đóng góp vui lòng để trong nhận xét.

Update: Đã thêm phần chia sẽ với vietkick.
Update: Mới thêm 2 widget ratingbest post.

Đọc tiếp >>

Cao Trong Hien

6 Dịch Vụ Cung Cấp SVN & Project Hosting


Nguồn mở (Open Source) đang chiếm ưu thế, ít nhất là hiện giờ. Và các dịch vụ online đang tăng cường nhảy vào các dịch vụ cộng đồng miễn phí, dĩ nhiên nó có ý nghĩa rất lớn đối với developers muốn lưu trữ (hosting), quản lý (manage), giới thiệu và chia sẽ online. Xin giới thiệu 6 SVN hosting miễn phí và cung cấp các tính năng cho quản lý dự án (project management) mà tôi biết.

Unfuddle – Một cái tên đẹp và một website trau chuốt. Dùng công nghệ web 2.0 cộng với chức năng theo dõi tiến độ dự án (project tracking), quản lý code (source control), thời gian (time tracking), các mốc dự án (milestones), vv... Gói miễn phí bao gồm 200MB lưu trữ và giới hạn thành viên(2), nó cũng không rộng rãi như Assembla không giới hạn thành viên nhóm.

Assembla – Một phần của gói các tính năng đầy đủ cho project management với một người dùng thường với 500MB bộ nhớ. Với $19, còn có thể đang tìm ứng viên cho project và một số tính năng như wiki , blogs,...

OpenSVN – Một phiên bản miễn phí đầu tiên của SVN hosting của các dự án nguồn mở và ta có thể thấy được sự “cổ kính” đó ngay khi bắt đầu vào trang và dùng các tính năng.

Bounty Source
– Cung cấp các tính năng như một SVN bình thường với wiki và CMS và quản lý công việc (task tracker). Bounty Source là server duy nhất có tính năng thanh toán tiền công cho developer theo số yêu cầu mà họ thực hiện được (bounties).

SourceForge
– Đã tồn tại từ khá lâu và cũng đã thể hiện được uy tín từ số năm tồn tại. Họ cũng cố gắng dùng các tính năng của Web2.0, tuy nhiên vẫn không thể trút bỏ hoàn toàn, bạn có thể thấy khi dùng các tính năng mà nó cung cấp.

Google Project Hosting
– Kế thừa đầy đủ các tính năng của SourceForge nên đầy đủ. Tuy nhiên, như đã đề cập trên thì nó nhìn cũ và tôi nghĩ Google không chăm sóc dịch vụ này tận tình lắm.

Đọc tiếp >>

Cao Trong Hien