Bài viết được tham khảo từ cuốn Design pattern for dummies
strategy
1. Giới thiệu về design pattern
Design Pattern là một kỹ thuật trong lập trình hướng đối tượng, nó khá quan trọng
và mọi lập trình viên muốn giỏi đều phải biết. Được sử dụng thường xuyên trong
các ngôn ngữ OOP. Nó sẽ cung cấp cho bạn các "mẫu thiết kế", giải pháp để giải
quyết các vấn đề chung, thường gặp trong lập trình. Các vấn đề mà bạn gặp phải có
thể bạn sẽ tự nghĩ ra cách giải quyết nhưng có thể nó chưa phải là tối ưu. Design
Pattern giúp bạn giải quyết vấn đề một cách tối ưu nhất, cung cấp cho bạn các giải
pháp trong lập trình OOP.
Trong Design Pattern có 3 nhóm bao gồm:
•
Creational Pattern (nhóm khởi tạo) gồm: Abstract Factory, Factory Method,
Singleton, Builder, Prototype. Nó sẽ giúp bạn trong việt khởi tạo đối tượng,
như bạn biết để khởi tạo bạn phải sử dụng từ khóa new, nhóm Creational
Pattern sẽ sử dụng một số thủ thuật để khởi tạo đối tượng mà bạn sẽ không
nhìn thấy từ khóa này.
•
Structural Pattern (nhóm cấu trúc) gồm: Adapter, Bridge, Composite,
Decorator, Facade, Proxy và Flyweight.. Nó dùng để thiết lập, định nghĩa
quan hệ giữa các đối tượng.
•
Behavioral Pattern gồm: Interpreter, Template Method, Chain of
Responsibility, Command, Iterator, Mediator, Memento, Observer, State,
Strategy và Visitor. Nhóm này dùng trong thực hiện các hành vi của đối
con. Và khi có càng nhiều lớp kế thừa liên quan, chúng cũng cần được bảo trì khi có
sự thay đổi và khi đó, bạn sẽ phải cập nhất phương thức go nhiều lần.
Vấn đề bạn cần phải giải quyết ở đây là làm sao để tránh được việc thay đổi ở các
lớp con, nếu không, bạn sẽ phải thay đổi code ở rất nhiều file để cập nhật được yêu
cầu của khách hàng.
Có lẽ là bạn cần một cách khác tốt hơn để xử lý vấn đề này thay vì sử dụng thừa
kế.
Nắm vững sự thay đổi từ “is-a” sang “has-a”
Với sự kế thừa, lớp cơ sở và các lớp con có một mối quan hệ “is-a”. Ví dụ , lớp
Helicopter có quan hệ “is-a” với lớp Vehicle, điều này có nghĩa Helicopter thừa kế
mọi thứ từ Vehicle, và nếu bạn phải chỉnh sửa các phương thức này, bạn sẽ gặp phải
vấn đề bảo trì nó trong tương lai. Lớp cơ sở xử lý phương thức theo một cách, và
lớp kế thừa lại thay đổi nó, và lớp kế tiếp lại thay đổi nó thêm một lần nữa. Và cuối
cùng bạn có một lô một lốc các biến thể của cùng 1 phương thức qua các lớp con.
Mặc khác, nếu bạn có thể trích những đoạn code dễ thay đổi và đóng gói chúng vào
đối tượng, bạn có thể sử dụng các đối tượng này khi cần. Nhiệm vụ mới là xử lý
trên các đối tượng này. Bạn đã không để việc xử lý lây lan qua các lớp con. Làm
như vậy sẽ cho phép bạn chỉnh sửa code của bạn bằng việc tạo ra “sự kết hợp”
composites các đối tượng. Với composites “kết hợp” này, bạn có thể dễ dàng chọn
ra và sử dụng đối tượng cần thiết. Một quan hệ “has-a” mới được tạo ra. Một đối
tượng StreetRacer sẽ có một “has-a” cách để di chuyển (go), đã được đóng gói vào
đối tượng. Một Helicopter sẽ có một cách riêng để di chuyển (go), và cũng được
đóng gói vào đối tượng. Từng đối tượng sẽ thực hiện hành động của riêng nó. Một
đối tượng, một nhiệm vụ thường là có ý nghĩa hơn là việc kế thừa các lớp, và tạo ra
hàng tá các lớp con. Nói cách khác, chúng ta sắp xếp lại dựa trên nhiệm vụ của lớp,
chứ không phải trên sự kế thừa.
Cách tạo thuật toán:
{
echo "Now I'm flying very fast";
}
}
Vậy là bạn đã tách được các phương thức xử lý ra khỏi các lớp cụ thể như
StreetRacer hay Helicopter rồi đấy. Bây giờ bạn đã có thể đưa các thuật toán này
vào sử dụng được rồi đấy.
Sử dụng thuật toán
Sau khi bạn tạo một đối tượng từ một thuật toán, bạn cần phải lưu trữ đối tượng ở
đâu đó. Vì vậy hãy thêm vào lớp cơ sở Vehicle, một phương thức mới
SetGoAlgorithm. Phương thức này sẽ quyết định thuật toán mà bạn muốn sử dụng.
abstract class Vehicle
{
private $goAlgorithm
public function setGoAlgorithm(GoAlgorithm $__goAlgorithm )
{
$goAlgorithm = $__goAlgorithm;
}
}
Bây giờ khi bạn muốn sử dụng một thuật toán cụ thể nào đó ở lớp kế thừa, tất cả
việc cần làm là gọi phương thức setGoAlgorithm với một đối tượng thuật toán
đúng. Phương thức go trong lớp Vehicle có chút thay đổi.
public function go()
{
$goAlgorithm->go();
}
•
Bạn muốn thay đổi thuật toán sử dụng khi chạy chương trình
Template Method
Định nghĩa
Xác định bộ xương của một thuật toán trong một hoạt động, trì hoãn một số bước
cho các lớp con. Phương thức mẫu cho phép các lớp con xác định lại các bước nhất
định của thuật toán mà không thay đổi cấu trúc của thuật toán.
Tần suất sử dụng:
Trung bình
Sơ đồ lớp UML
Các lớp và đối tượng tham gia:
AbstractClass (DataObject):
o
định nghĩa các hoạt động nguyên thủy trừu tượng mà các lớp con cụ
thể xác định để thực hiện các bước của thuật toán
o
thực hiện một phương thức mẫu xác định bộ xương của thuật
toán. Phương thức mẫu gọi các hoạt động nguyên thủy cũng như các
hoạt động được xác định trong AbstractClass hoặc các hoạt động của
các đối tượng khác.
7.
/// Template Design Pattern.
8.
/// </summary>
9.
class MainApp
10.
{
11.
/// <summary>
12.
/// Entry point into console application.
13.
/// </summary>
14.
Console.ReadKey();
}
24.
25.
}
26.
27.
/// <summary>
28.
/// The 'AbstractClass' abstract class
29.
/// </summary>
30.
abstract class AbstractClass
31.
{
Console.WriteLine("");
}
41.
42.
}
43.
44.
/// <summary>
45.
/// A 'ConcreteClass' class
46.
/// </summary>
47.
class ConcreteClassA : AbstractClass
48.
57.
}
58.
59.
/// <summary>
60.
/// A 'ConcreteClass' class
61.
/// </summary>
62.
class ConcreteClassB : AbstractClass
63.
{
64.
public override void PrimitiveOperation1()
73.
74.
75.
76.
Output
ConcreteClassA.PrimitiveOperation1()
ConcreteClassA.PrimitiveOperation2()
Mã thế giới thực trong C #
Mã trong thế giới thực này biểu thị một phương thức Mẫu có tên Run () cung cấp
một chuỗi các phương thức gọi bộ xương. Việc thực hiện các bước này được
chuyển đến lớp con CustomerDataObject, thực hiện các phương thức Kết nối,
Chọn, Xử lý và Ngắt kết nối.
1.
using System;
2.
using System.Data;
3.
using System.Data.OleDb;
4.
{
13.
/// <summary>
14.
/// Entry point into console application.
15.
/// </summary>
16.
static void Main()
{
17.
18.
DataAccessObject daoCategories = new Categories();
19.
daoCategories.Run();
/// The 'AbstractClass' abstract class
31.
/// </summary>
32.
abstract class DataAccessObject
33.
{
34.
protected string connectionString;
35.
protected DataSet dataSet;
36.
37.
public virtual void Connect()
38.
public abstract void Process();
47.
48.
public virtual void Disconnect()
49.
{
connectionString = "";
50.
51.
}
52.
53.
// The 'Template Method'
54.
public void Run()
55.
{
/// A 'ConcreteClass' class
65.
/// </summary>
66.
class Categories : DataAccessObject
67.
{
68.
public override void Select()
69.
{
70.
string sql = "select CategoryName from Categories";
71.
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(
82.
DataTable dataTable = dataSet.Tables["Categories"];
83.
foreach (DataRow row in dataTable.Rows)
84.
{
Console.WriteLine(row["CategoryName"]);
85.
86.
}
87.
Console.WriteLine();
}
88.
89.
}
90.
91.
99.
OleDbDataAdapter dataAdapter = new OleDbDataAdapter(
100.
sql, connectionString);
101.
102.
dataSet = new DataSet();
103.
dataAdapter.Fill(dataSet, "Products");
}
104.
105.
106.
public override void Process()
107.
{
116.
117.
118.
119.
120.
}
Output
Categories ---Beverages
Condiments
Confections
Dairy Products
Grains/Cereals
Meat/Poultry
Produce
Seafood
Products ---Chai
Chang
Aniseed Syrup
Chef Anton's Cajun Seasoning
Chef Anton's Gumbo Mix
Grandma's Boysenberry Spread
Uncle Bob's Organic Dried Pears
Northwoods Cranberry Sauce
Mishi Kobe Niku
1. Visitor Patern là gì
truy cập.
Bước 1
Xác định một giao diện để đại diện cho yếu tố.
Máy tínhPart.java
public interface ComputerPart {
public void accept(ComputerPartVisitor computerPartVisitor);
}
Bước 2
Tạo các lớp bê tông mở rộng lớp trên.
Bàn phím.java
public class Keyboard implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
Monitor.java
public class Monitor implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
Chuột.java
public class Mouse implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
Máy tínhPartDisplayVisitor.java
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@Override
public void visit(Computer computer) {
System.out.println("Displaying Computer.");
}
@Override
public void visit(Mouse mouse) {
System.out.println("Displaying Mouse.");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("Displaying Keyboard.");
}
@Override
public void visit(Monitor monitor) {
System.out.println("Displaying Monitor.");
}
}
Bước 5
Sử dụng ComputerPartDisplayVisitor để hiển thị các phần của Máy tính .
VisitorPotypeDemo.java
public class VisitorPatternDemo {
public static void main(String[] args) {
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
}
}