Design Pattern

Template Method Pattern – Khuôn mẫu cho tất cả

Template Method Pattern

Chào mọi người, hôm nay mình sẽ tiếp tục loạt bài về Design Pattern với một pattern mới: Template Method Pattern. Từ template làm chúng ta liên tưởng đến các template trong thiết kế web, khi chúng ta có 1 trang templae đã có sẵn header, footer, navigation, chỉ riêng phần boby là để trống và sẽ display nội dung theo từng page. Nghĩa là chỉ có phần body là sẽ thay đổi theo từng page, còn các phần khác sẽ giống nhau cho tất cả các page. Trừ 1 số page đặc biệt mà nội dung của header, footer, navigation sẽ thay đổi. Việc làm này sẽ giúp giảm thiểu các công việc giống nhau ở nhiều nơi. Thay vì phải viết tất cả các thành phần ở mỗi page, thì bây giờ các thành phần chung sẽ được gom lại và đặt trong một template.

Trong lập trình, khái niệm template cũng tương tự như vậy. Nếu các bạn đã từ sử dụng từ khóa abstract trong Java thì khả năng cao là chính các bạn cũng đang sử dụng mẫu template này đấy.

Hãy cụ thể hóa bài toán web template ở trên vào ngôn ngữ lập trình minh họa bằng Java.

Đầu tiên hãy xây dựng một lớp PageTemplate

PageTemplate.java

package behavior.templatemethod;

public abstract class PageTemplate {

	protected void displayHeader() {
		System.out.println("HEADER");
	}

	protected void displayNavigation() {
		System.out.println("NAVIGATION");
	}

	protected void displayFooter() {
		System.out.println("FOOTER");
	}

	/**
	 * Let each subclass define it own content
	 * @author Edward
	 */
	protected abstract void displayBody();

	/**
	 * Display all content of web page
	 * @author Edward
	 */
	public void displayWebPage() {
		displayHeader();
		displayNavigation();
		displayBody();
		displayFooter();
	}
}

Lớp PageTemplate đã có sẵn các phương thức để hiển thị các thành phần header, footer, navigation. Riêng phương thức displayBody sẽ là abstract method, các trang khác nhau sẽ có nội dung hiển thị khác nhau. Sau đó cùng hiển thị tất cả lên màn hình theo một thứ tự đã cho trước trong hàm displayWebPage. Bây giờ hãy tạo ra 1 số trang sử dụng template này.

DesignPatternPage.java

package behavior.templatemethod;

public class DesignPatternPage extends PageTemplate {
	@Override
	protected void displayBody() {
		System.out.println("DESIGN PATTERN CONTENT");
	}
}

Java8TutorialPage.java

package behavior.templatemethod;

public class Java8TutorialPage extends PageTemplate {
	@Override
	protected void displayBody() {
		System.out.println("JAVA 8 TUTORIAL CONTENT");
	}
}

ContactPage.java

package behavior.templatemethod;

public class ContactPage extends PageTemplate {
	@Override
	protected void displayBody() {
		System.out.println("ABOUT CONTENT");
	}

	@Override
	protected void displayNavigation() {
		// We do NOT want to display Navigation here
		// Just do nothing
	}
}

Các lớp trên đều kế thừa từ lớp PageTemplate. Chúng có một yêu cầu bắt buộc là phải implement lại method displayBody để hiển thị nội dung cho từng trang. Riêng có lớp ContactPage sẽ implement lại method displayNavigation để không hiển thị gì. Viết một lớp để test tất cả:

TemplateMethodTest.java

package behavior.templatemethod;

public class TemplateMethodTest {

	public static void main(String[] args) {
		PageTemplate designPattern = new DesignPatternPage();
		designPattern.displayWebPage();

		System.out.println();

		PageTemplate java8Tutorial = new Java8TutorialPage();
		java8Tutorial.displayWebPage();

		System.out.println();

		PageTemplate contact = new ContactPage();
		contact.displayWebPage();
	}

}

Kết quả khi output:

HEADER
NAVIGATION
DESIGN PATTERN CONTENT
FOOTER

HEADER
NAVIGATION
JAVA 8 TUTORIAL CONTENT
FOOTER

HEADER
ABOUT CONTENT
FOOTER

Cùng xem qua Class diagram mối quan hệ giữa các class với nhau

TemplateMethod_ClassDiagram

Như ta thấy, tất cả các page sẽ đều có chung các thành phần trong template đã định nghĩa, chúng chỉ cần implement lại những thành phần mà CHỈ CÓ RIÊNG nó mới quyết định được. Vậy nguyên lý của Template Method pattern này là: Đặt tất cả những xử lý chung trong lớp cha, sau đó định nghĩa các hàm abstract và để các lớp con tự định nghĩa lấy. Việc này sẽ giảm thiểu sự trùng lặp code và dễ dàng bảo trì về sau khi mỗi lớp con cần có sự thay đổi.

Các bạn có thể tham khảo thêm các bài viết về Design Pattern trong Series về Design Pattern

Nguồn: https://edwardthienhoang.wordpress.com

Email: edwardthienhoang@gmail.com

Design Pattern

Facade pattern – Đơn giản hóa tất cả

Facade pattern

Chào mọi người, hôm nay mình sẽ tiếp tục loạt bài về Design Pattern với một pattern mới: Facade Pattern. Cái tên nghe rất lạ nhưng khi bước vào implement, các bạn sẽ thấy đây là mẫu pattern gần gũi và được sử dụng nhiều nhất trong chương trình.

Định nghĩa

Nói một cách đơn giản như chính việc implement pattern này, giúp Client đơn giản hóa các lời gọi hàm từ nhiều object khác nhau bằng cách cung cấp 1 interface đơn giản hơn để Client làm việc. Điều này giúp đơn giản hóa và giảm độ phụ thuộc của Client đến các object bên trong.

Hình phía dưới sẽ minh họa cho điều mình vừa nói ở trên:

facade

Các Client thay vì phải gọi vào nhiều component phía trong, đối tượng Facade sẽ đảm nhiệm việc đó và cung cấp các interface đơn giản hơn đến Client.

Ví dụ

Hãy lấy một ví dụ có sẵn trong Java Swing, lớp javax.swing.JOptionPane:

facade_advanced2

JOptionPane được thiết kế như một đối tượng Facade. Thay vì phải gọi trực tiếp đến các lớp phía trong như: JDialog, BorderFactory, Panel… để tạo ra các dialog như: Confirm, Input, Message and OptionDialogs. Thì bây giờ chỉ cần thông qua JOptionPane, nó sẽ giúp chúng ta làm chuyện đó.

Dưới đây là 1 ví dụ nếu không sử dụng JOptionPane

...
JFrame frame = new JFrame("My Message Dialog");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Quit");
JLabel label = new JLabel("This is My Message Dialog!");

ActionListener actionListener = new ActionListener() {
	public void actionPerformed(ActionEvent actionEvent) {
		System.exit(0);
	}
};

button.addActionListener(actionListener);
Container contentPane = frame.getContentPane();
contentPane.add(label, BorderLayout.CENTER);
contentPane.add(button, BorderLayout.SOUTH);
frame.setSize(300, 200);
frame.setVisible(true);
...

Quá phức tạp và quá nhiều phụ thuộc. Nếu sử dụng JOptionPane như là 1 Facade thì mọi chuyện sẽ chỉ đơn giản như dưới đây:

...
JOptionPane optionPane = new JOptionPane(
	"This Dialog is generated by the JOptionPane Facade!",
	JOptionPane.OK_OPTION);
// OR
JDialog dialog = optionPane.createDialog(frame.getContentPane(),
	"JOptionPane Message Dialog");
	dialog.setVisible(true);
...

Kết thúc bài viết về Facade Pattern tại đây. Các bạn chỉ cần nhớ 1 điều, khi có nhiều lời gọi qua nhiều lớp đối tượng hãy nghĩ đến Facade để đơn giản hóa chúng, mọi thay đổi trong các lời gọi hàm sẽ được thực hiện trong lớp Facade mà không ảnh hưởng đến chương trình.

Có một mẫu design cũng gói lại nhiều lớp đối tượng để đưa ra những xử lý đơn giản hơn đó là Mediator Pattern. Trong khi Facade Pattern hướng đến việc cung cấp những API đơn giản hơn từ đến Client, thì Mediator sẽ dùng cho mục đích khác, tách biệt nhiều xử lý phức tạp trong các lớp đối tượng, và có thể thêm hoặc bớt bất cứ thành phần nào trong đó. Cùng đọc về Mediator Pattern để đưa ra sự so sánh chính xác nhất với 2 Pattern này.

Các bạn có thể tham khảo thêm các bài viết về Design Pattern trong Series về Design Pattern

NGUỒN: HTTP://EDWARDTHIENHOANG.WORDPRESS.COM/

EMAIL: EDWARDTHIENHOANG@GMAIL.COM