Monday, September 24, 2007

Các mẫu thiết kế hướng đối tượng (P.3)

BEHAVIORAL PATTERNS



Mẫu Behavioral có liên quan đến luồng điều khiển của hệ thống. Một vài cách của tổ chức điều khiển bên trong một hệ thống để có thể nâng mang lại các lợi ích cả về hiệu suất lẫn khả năng bảo trì hệ thống đó



2.1.Chain of Responsibility

- Ý nghĩa
Mẫu này thiết lập một chuỗi bên trong một hệ thống, nơi mà các thông điệp hoặc có thể được thực hiện ở tại một mức nơi mà nó được nhận lần đầu hoặc là được chuyển đến một đối tượng mà có thể thực hiện điều đó
- Mô hình mẫu





Trong đó:
o Handler: là một giao tiếp định nghĩa phương thức sử dụng để chuyển thông điệp qua các lần thực hiện tiếp theo.
o ConcreteHandler: là một thực thi của giao tiếp Handler. Nó giữ một tham chiếu đến một Handler tiếp theo. Việc thực thi phương thức handleMessage có thể xác định làm thế nào để thực hiện phương thức và gọi một handlerMethod, chuyển tiếp thông điệp đến cho Handler tiếp theo hoặc kết hợp cả hai

- Trường hợp ứng dụng
o Có một nhóm các đối tượng trong một hệ thống có thể đáp ứng tất cả các loại thông điệp giống nhau
o Các thông điệp phải được thực hiện bởi một vài các đối tượng trong hệ thống
o Các thông điệp đi theo mô hình “thực hiện – chuyển tiếp”, một vài sự kiện có thể được thực hiện tại mức mà chúng được nhận hoặc tại ra, trong khi số khác phải được chuyển tiếp đến một vìa đối tượng khác

- Ví dụ mãu

Hệ thống quản lý thông tin các nhân có thể được sử dụng để quản lý các dự án như là các liên hệ.
Ta hình dung một cấu trúc cây như sau; đỉnh là một dự án, các đỉnh con là các tác vụ của dự án đó, và cứ như vậy, mỗi đỉnh con tác vụ lại có một tập các đỉnh con tác vụ khác.

Để quản lý cấu trúc này ta thực hiện như sau:
-Ở mỗi đỉnh ta lưu các thông tin như sau: tên tác vụ, đỉnh cha, tập các đỉnh con
-Ta xét thông điệp sau: duyệt từ đỉnh gốc (project cở sở) in ra các thông tin
-Như vậy với thông điệp này, việc in thông tin ở một đỉnh là chưa đủ, ta phải chuyển tiếp đến in thông tin các đỉnh con của đỉnh gốc và chuyển tiếp cho đến khi không còn đỉnh con thì mới dừng





Giao tiếp TaskItem định nghĩa các phương thức cho project cơ sở và các tác vụ


public interface TaskItem{
public TaskItem getParent();
public String getDetails();
public ArrayList getProjectItems();
}



Lớp Project thực thi giao tiếp TaskItem, nó là lớp đại diện cho các đỉnh gốc trên cùng của cây

public class Project implements TaskItem {
private String name;
private String details;
private ArrayList subtask = new ArrayList();

public Project(){ }
public Project(String newName, String newDetails){
name = newName;
details = newDetails;
}

public String getName(){
return name;
}
public String getDetails(){
return details;
}
public ProjectItem getParent(){
return null;
//vì project là ở mức cơ sở, đỉnh gốc trên cùng nên không có cha
}
public ArrayList getSubTask(){
return subtask;
}

public void setName(String newName){
name = newName;
}
public void setDetails(String newDetails){
details = newDetails;
}

public void addTask(TaskItem element){
if (!subtask.contains(element)){
subtask.add(element);
}
}

public void removeProjectItem(TaskItem element){
subtask.remove(element);
}
}




Lớp Task thực thi giao tiếp TaskItem, nó đại diện cho các tác vụ, các đỉnh không phải ở gốc của cây


public class Task implements TaskItem {
private String name;
private ArrayList subtask = new ArrayList();
private String details;
private TaskItem parent;

public Task(TaskItem newParent){
this(newParent, "", "");
}
public Task(TaskItem newParent, String newName, String newDetails,){
parent = newParent;
name = newName;
details = newDetails;
}

public String getDetails(){
if (primaryTask){
return details;
}
else{
return parent.getDetails() + EOL_STRING + "\t" + details;
}
}

public String getName(){
return name;
}
public ArrayList getSubTask(){ return subtask; }
public ProjectItem getParent(){
return parent;
}

public void setName(String newName){
name = newName;
}
public void setParent(TaskItem newParent){
parent = newParent;
}
public void setDetails(String newDetails){
details = newDetails;
}

public void addSubTask(TaskItem element){
if (!subtask.contains(element)){
subtask.add(element);
}
}

public void removeSubTask(TaskItem element){
subtask.remove(element);
}
}



Lớp thực thi test mẫu


public class RunPattern{
public static void main(String [] arguments){
Project project = new Project(“Project 01”, “Detail of Project 01”);
//Khởi tạo, thiết lập các tác vụ con …
detailInfor(project);
}

private static void detailInfor (TaskItem item){
System.out.println("TaskItem: " + item);
System.out.println(" Details: " + item.getDetails());
System.out.println();
if (item.getSubTask() != null){
Iterator subElements = item.getSubTask().iterator();
while (subElements.hasNext()){
detailInfor ((TaskItem)subElements.next());
}
}
}
}




Gọi thông điệp detailInfor(item) và thông điệp này được chuyển tiếp nhiều lần qua nhiều đối tượng thực thi

2.2.Command Pattern
- Ý nghĩa
Gói một mệnh lệnh vào trong một đối tượng mà nó có thể được lưu trữ, chuyển vào các phương thức và trả về một vài đối tượng khác

- Cấu trúc mẫu




Trong đó:
o Command: là một giao tiếp định nghĩa các phương thức cho Invoker sử dụng
o Invoker: lớp này thực hiện các phương thức của đối tượng Command
o Receiver: là đích đến của Command và là đối tượng thực hiện hoàn tất yêu cầu, nó có tất cả các thông tin cần thiết để thực hiện điều này
o ConcreteCommand: là một thực thi của giao tiếp Command. Nó lưu giữa một tham chiếu Receiver mong muốn

Luồng thực thi của mẫu Command như sau:



o Client gửi yêu cầu đến GUI của ứng dụng
o Ứng dụng khởi tạo một đối tượng Command thích hợp cho yêu cầu đó (đối tượng này sẽ là các ConcreteCommand)
o Sau đó ứng dụng gọi phương thức executeCommand() với tham số là đối tượng Command vừa khởi tạo
o Invoker khi được gọi thông qua phương thức executeCommand() sẽ thực hiện gọi phương thức execute() của đối tượng Command tham số
o Đối tượng Command này sẽ gọi tiếp phương thức doAction() của thành phần Receiver của nó, được khởi tạo từ đầu, doAction() chính là phương thức chính để hoàn tất yêu cầu của Client

- Trường hợp áp dụng
o Hỗ trợ undo, logging hoặc transaction
o Thực hiện hàng đợi lệnh và thực hiện lệnh tại các thời điểm khác nhau
o Hạn chế sự chặt chẽ của yêu cầu với đối tượng thực hiện hoàn tất yêu cầu đó

- Ví dụ mẫu

public interface Command{
public void execute();
}

public class ConcreteCommand implements Command{
private Receiver receiver;
public void setReceiver(Receiver receiver){
this.receiver = receiver;
}
public Receiver getReceiver(){
return this.receiver;
}

public void execute (){
receiver.doAction();
}
}

public class Receiver{
private String name;
public Receiver(String name){
this.name = namel
}
public void doAction(){
System.out.print(this.name + “ fulfill request!”);
}
}

public class Invoker{
public void executeCommand(Command command){
command.execute();
}
}

public class Run{
public static void main(String[] agrs){
Command command = new ConcreteCommand();
command.setReceiver(new Receiver(“NguyenD”));
Invoker invoker = new Invoker();
Invoker.executeCommand(command);
}
}



2.3.Interpreter Pattern
- Ý nghĩa
o Ý tưởng chính của Interpreter là triển khai ngôn ngữ máy tính đặc tả để giải quyết nhanh một lớp vấn đề được định nghĩa. Ngôn ngữ đặc tả thường làm cho vấn đề được giải quyết nhanh hơn ngôn ngữ thông thường từ một cho đến vài trăm lần
o Ý tưởng tương tự như vậy biểu diễn các biểu thức tính toán theo cú pháp Ba Lan

- Mô hình mẫu




Trong đó:
o Expression: là một giao tiếp mà thông qua nó, client tương tác với các biểu thức
o TerminalExpression: là một thực thi của giao tiếp Expression, đại diện cho các nốt cuối trong cây cú pháp
o NonterminalExpression: là một thực thi khác của giao tiếp Expression, đại diện cho các nút chưa kết thúc trong cấu trúc của cây cú pháp. Nó lưu trữ một tham chiếu đến Expression và triệu gọi phương thức diễn giải cho mỗi phần tử con
o Context: chứa thông tin cần thiết cho một vài vị trí trong khi diễn giải. Nó có thể phục vụ như một kênh truyền thông cho các thể hiện của Expression
o Client: hoặc là xây dựng hoặc là nhận một thể hiện của cây cú pháp ảo. Cây cú pháp này bao gồm các thể hiện của TerminalExpression và NoterminalExpression để tạo nên câu đặc tả. Client triệu gọi các phương thức diễn giải với ngữ cảnh thích hợp khi cần thiết

- Trường hợp ứng dụng
o Có một ngôn ngữ đơn giản để diễn giải vấn đề
o Các vấn đề lặp lại có thể được diễn giải nhanh bằng ngôn ngữ đó

- Ví dụ mẫu
Xét biểu thức 5 + 3 x 3 + 6, với bài tóan này ta có thể chia thành các bài các bài tóan nhỏ hơn
-Tính 3 x 3 = a
-Sau đó tính 5 + a = b
-Sau đó tính b + 6
Ta biểu diễn bài tóan thành cấu trúc cây và duyệt cây theo Ba Lan (hay Ba Lan đảo gì đó không còn nhớ nữa)





Mã nguồn cho ví dụ này như sau



import java.util.Stack;
public class Context extends Stack {
}

public interface Expression {
public void interpret(Context context);
}

public class TerminalExpressionNumber implements Expression {
private int number;

public TerminalExpressionNumber(int number){
this.number = number;
}
public void interpret(Context context) {
context.push(this.number);
}
}

public class TerminalExpressionPlus implements Expression {

public void interpret(Context context) {
//Cong 2 phan tu phia tren dinh Stack
context.push(context.pop() + context.pop());
}
}

public class TerminalExpressionMutil implements Expression{
public void interpret(Context context) {
//Nhan 2 phan tu phia tren dinh Stack
context.push(context.pop() * context.pop());
}
}

import java.util.ArrayList;
public class NonterminalExpression implements Expression {

private ArrayList expressions;//tham chieu den mang Exoression con

public ArrayList getExpressions() {
return expressions;
}

public void setExpressions(ArrayList expressions) {
this.expressions = expressions;
}

public void interpret(Context context) {
if (expressions != null){
int size = expressions.size();
for (Expression e : expressions){
e.interpret(context);
}
}
}
}

import java.util.*;
public class Client {
public static void main(String[] agrs){
Context context = new Context();

// 3 3 *
ArrayList treeLevel1 = new ArrayList ();
treeLevel1.add(new TerminalExpressionNumber(3));
treeLevel1.add(new TerminalExpressionNumber(3));
treeLevel1.add(new TerminalExpressionMutil());

// 5 (3 3 *) +
ArrayList treeLevel2 = new ArrayList ();
treeLevel2.add(new TerminalExpressionNumber(5));
Expression nonexpLevel1 = new NonterminalExpression();
((NonterminalExpression)nonexpLevel1).setExpressions(treeLevel1);
treeLevel2.add(nonexpLevel1);
treeLevel2.add(new TerminalExpressionPlus());

// (5 (3 3 *) +) 6 +
ArrayList treeLevel3 = new ArrayList ();
Expression nonexpLevel2 = new NonterminalExpression();
((NonterminalExpression)nonexpLevel2).setExpressions(treeLevel2);
treeLevel3.add(nonexpLevel2);
treeLevel3.add(new TerminalExpressionNumber(6));
treeLevel3.add(new TerminalExpressionPlus());

for(Expression e : treeLevel3){
e.interpret(context);
}

if (context != null)
System.out.print("Ket qua: " + context.pop());
}
}


No comments:

Post a Comment