Design pattern trong PHP (phần 1)
Bài đăng này đã không được cập nhật trong 3 năm
Design pattern là gì ?
Design Pattern là bộ môn thuộc về ngành khoa học máy tính chuyên nghiên cứu các kiên trúc phần mềm. Hiện nay tất cả các Framwork như Codeigniter, Zend, Laravel, ... đều có sử dụng nhữ kiến trúc design pattern có sẵn và mỗi Framwork sẽ có những kiểu design partern riêng. Design Pattern sử dụng nền tảng của lập trình hướng đối tượng, áp dụng các tính chất như tính kế thừa, hàm khởi tạo, tính đa hình, ... để làm nên những kiến trúc phần mềm đáp ứng cho project của họ.
Một ví dụ điển hình về design pattern và được biết đến nhiều nhất tron PHP là cấu trúc MVC
Ngoài ra còn một số pattern sau chúng ta sẽ từ từ tìm hiểu
Danh sách các mẫu design pattern
Tham khảo từ wikipedia
Các mẫu tạo lập
(creational patterns)
- Abstract factory pattern
- Builder
- Factory method pattern
- Prototype
- Singleton
Các mẫu cấu trúc
(structural patterns)
- Adapter
- Bridge
- Composite
- Decorator
- Facade
- Flyweight
- Proxy
Các mẫu ứng xử
(behavioral patterns)
- Chain of responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template method
- Visitor
Dĩ nhiên danh sách trên là chưa đầy đủ, nhưng ở bài viết này, mình sẽ chỉ giới thiệu về các pattern được ứng dụng nhiều trong PHP cũng như các ngôn ngữ OOP khác.
Factory Pattern
Mẫu này được chia làm 2 loại là Factory Method và Abtract Factory. Vậy sự khác nhau giữa 2 pattern này là gì ? Hãy cùng tìm hiểu qua 2 ví dụ để tìm ra sự khác biệt.
1. Factory method
Định nghĩa
Bản chất của mẫu thiết kế Factory là "Định nghĩa một giao diện (interface) cho việc tạo một đối tượng, nhưng để các lớp con quyết định lớp nào sẽ được tạo. "Factory method" giao việc khởi tạo một đối tượng cụ thể cho lớp con."
Gỉa sử, chúng ta xây dựng 1 "nhà máy" (factory) để "sản xuất" ra các hình vẽ khác nhau, hãy xem mô hình UML dưới đây.
Có hiểu đơn giản, chúng ta có 1 nhà máy (ở đây là ShapeFactory), và cần nhà máy này sản xuất ra các hình vẽ theo yêu cầu, mà không cần quan nó sẽ dùng tâm phương pháp hay cách thức nào để tạo ra hình vẽ đó. Đây cũng chính là mục đích của việc sử dụng Factory Method.
Cách thực hiện
Vậy để triển khai mẫu Factory Method phải làm như thế nào ?
- Đầu tiên chúng ta cần tạo ra 1 interface(hoặc abstract class) ở đây tôi đặt tên là
Shape
, trong đó có phương thứcdraw()
đây là phương thức để vẽ các hình. - Tiếp theo là tạo ra các subclass, ví dụ tạo class
Circle
kế thừa class/ hoặc implements interfaceShape
, class này sẽ override lại phương thứcdraw()
củaShape
đã tạo để vẽ ra hình tròn. - Tiếp theo chúng ta tạo class
Square
cũng kế thừaShape
, class này sẽ định nghĩa lại phương thứcdraw()
để vẽ ra hình vuông. - Tương tự với class Rectangle để tạo ra hình chữ nhật.
- Và quan trọng nhất là thực hiện Factory Method bằng cách tạo ra class
ShapeFactory
, tôi sẽ nói rõ hơn ở phần dưới đây.
Ví dụ
Trước hết chúng ta tạo file Shape.php với nội dung như sau
<?php
interface Shape {
// Có thể định nghĩa sẵn const hoặc không :D
const SQUARE = 1;
const CIRCLE = 2;
const RECTANGLE = 3;
// general method
function draw();
}
Tiếp theo là tạo 3 class implements interface Shape
<?php
class Circle implements Shape
{
public function draw() {
// thực hiện code vẽ hình tròn tại đây
echo "Draw circle";
}
}
<?php
class Square implements Shape
{
public function draw() {
// thực hiện code vẽ hình vuông tại đây
echo "Draw square";
}
}
<?php
class Rectangle implements Shape
{
public function draw() {
// thực hiện code vẽ hình chữ nhật tại đây
echo "Draw rectangle";
}
}
Cuối cùng để thực hiện Factory Method, chúng ta tạo ra lớp ShapeFactory như dưới đây. Class này sẽ tạo ra các đối tượng cụ thể tại thời điểm thực thi (at run time)
<?php
class ShapeFactory
{
public function getShape($type) {
switch ($type) {
case Shape::SQUARE:
return new Square;
break;
case Shape::CIRCLE:
return new Circle;
break;
case Shape::RECTANGLE:
return new Rectangle;
break;
default:
return null
break;
}
return null;
}
}
getShape
chính là factory method, với tham số truyền vào là kiểu hình vẽ muốn khởi tạo. Đây chính là mấu chốt của việc thực hiện pattern này .
Và cuối cùng, chúng ta sẽ tạo ra các đối tượng cụ thể, hay các hình vẽ như sau.
<?php
$factory = new ShapeFactory();
// hình tròn Shape::CIRCLE
$shapeCircle = $factory->getShape(Shape::CIRCLE);
$shapeCircle->draw();
=> in ra màn hình Draw circle
Tương tự, vẽ các hình khác chỉ cần thay đổi giá trị của $type trong getShape($type)
thành định danh của hình vuống hay chữ nhật ta sẽ lấy được object mong muốn.
Như vậy chúng ta ó thể thấy rõ ràng là chúng ta không cần biết phương thức draw
kia thực hiện bằng cách nào mà chỉ cần yêu cầu từ 'factory', nhiệm vụ còn lại là factory sẽ phải cung cấp chính xác điều mà chúng ta muốn.
2. Abstract Factory Pattern
Định nghĩa
Là thiết kế mẫu hướng đối tượng trong việc thiết kế phần mềm, cung cấp một giao diện lớp có chức năng tạo ra một tập hợp các đối tượng liên quan hoặc phụ thuộc lẫn nhau mà không chỉ ra đó là những lớp cụ thể nào tại thời điểm thiết kế.[1] Mẫu thiết kế Abstract Factory đóng gói một nhóm những lớp đóng vai trò "sản xuất" (Factory) trong ứng dụng, đây là những lớp được dùng để tạo lập các đối tượng. Các lớp sản xuất này có chung một giao diện lập trình được kế thừa từ một lớp cha thuần ảo gọi là "lớp sản xuất ảo".
Có thể hiểu đơn giản Abstract Factory như 1 siêu nhà máy dùng để tạo ra các nhà máy (factory) khác.
Cấu trúc
- AbstractFactory: định nghĩa một giao tiếp cho thao tác khởi tạo các "sản phẩm" ảo (AbstractProduct)
- ConcreteFactory: thực thi giao tiếp AbstractFactory để tạo ra đối tượng cụ thể
- AbstractProduct: định nghĩa một lớp ảo cho một loại đối tương "sản phẩm"
- Product: kế thừa từ từ lớp "sản phẩm" ảo AbstractProduct, các lớp Product định nghĩa từ đối tượng cụ thể
- Client: sử dụng các lớp AbstractFactory và AbstractProduct trong hệ thống
Ví dụ
Sơ đồ UML mô tả 1 dạng Abstract Factory
Như chúng ta thấy, khác với Factory Method, ở hình vẽ có thêm 1 lớp Producer, vai trò tương tự với lớp Factory ở phần 1. Có thể nói đây là 1 mô hình mở rộng của pattern Factory Method.
Bước 1
Tạo interface Shape (được hiểu là 1 AbstractProduct
)
<?php
interface Shape {
// Có thể định nghĩa sẵn const hoặc không :D
const SQUARE = 1;
const CIRCLE = 2;
const RECTANGLE = 3;
// general method
function draw();
}
Bước 2
Tạo các class cụ thể implements cùng 1 interface Shape
, đây chính là các Product
đã được nhắc đến ở trên.
<?php
class Circle implements Shape
{
public function draw() {
// thực hiện code vẽ hình tròn tại đây
echo "Draw circle";
}
}
<?php
class Square implements Shape
{
public function draw() {
// thực hiện code vẽ hình vuông tại đây
echo "Draw square";
}
}
<?php
class Rectangle implements Shape
{
public function draw() {
// thực hiện code vẽ hình chữ nhật tại đây
echo "Draw rectangle";
}
}
Bước 3
Tạo interface Color (1 AbstractProduct
tương tự Shape)
<?php
interface Color {
// general method
function fill();
}
Bước 4
Tương tự bước 2, tạo các class và implements cùng 1 interface Color
, dĩ nhiên cũng là dạng sản phẩm - Product
, của nhà máy - Factory
<?php
class Red implements Color
{
public function fill() {
echo "Filled red";
}
}
<?php
class Green implements Color
{
public function fill() {
echo "Filled green";
}
}
<?php
class Blue implements Color
{
public function draw() {
echo "Filled blue";
}
}
Bước 5
Tạo ra 1 lớp Abstract với phương thức giáo tiếp đến thao tác khởi tạo các Shape và Color object - đây chính là khái niệm AbstractFactory
được định nghĩa ở trên.
<?php
abstract class AbstractFactory {
abstract function getColor($color);
abstract function getShape($shape) ;
}
Bước 6
Tạo lớp Factory kế thừa AbstractFactory để thực hiện generate ra các object cụ thể dựa trên các thông tin được đưa ra. Các lớp này còn được gọi là ConcreteFactory
.
Shape Factory
<?php
class ShapeFactory extends AbstractFactory
{
public function getShape($type) {
switch ($type) {
case Shape::SQUARE:
return new Square;
break;
case Shape::CIRCLE:
return new Circle;
break;
case Shape::RECTANGLE:
return new Rectangle;
break;
default:
return nullbreak;
}
return null;
}
}
Color Factory
<?php
class ColorFactory extends AbstractFactory
{
public function getColor($color) {
switch (strtolower($color)) {
case 'red':
return new Red();
break;
case 'blue':
return new Blue()
break;
case 'green':
return new Green()
break;
default:
return null
break;
}
return null;
}
}
Bước 7
Tạo FactoryProducer để khởi tạo 1 abstract Shape/Color Factory
<?php
class FactoryProducer {
public static function getFactory($choice)
{
$choice = strtolower($choice);
if($choice == 'shape'){
return new ShapeFactory;
} elseif($choice == 'color')){
return new ColorFactory;
}
return null;
}
}
Bước 8
Như vậy là đã gần đầy đủ 1 mô hình AbstractFactory, chúng ta chỉ cần phần Client
để sử dụng AbstractFactory và AbstractProduct trong hệ thống/apps của mình.
Tạo 1 file php bất kì để test thôi
<?php
// dĩ nhiên là cần include các class cần sử dụng
include ...
// khởi tạo lớp ShapeFactory (tạo ra "nhà máy")
$shapeFactory = FactoryProducer::getFactory('shape');
// lấy object Shape với kiểu hình là Circle (lấy "sản phẩm")
$shape = $shapeFactory->getShape(Shape::CIRCLE);
//gọi method draw từ Shape Circle (sử dụng)
$shape->draw();
//Tương tự với màu sắc
$colorFactory = FactoryProducer::getFactory('color');
$color= $shapeFactory->getColor('red');
$color->fill();
Bước 9
Cùng xem output
>Draw circle
>Filled red
```
# Kết
Ở bài viết này tôi đã giới thiệu khá cụ thể về 2 pattern thuộc Factory, tôi sẽ tìm hiểu tiếp về các pattern thông dụng nhất và sẽ chia sẻ lại trong các bài viết sau :D
Nguồn tham khảo:
- [**Wikipedia**](http://en.wikipedia.org/wiki/Software_design_pattern)
- [**Tutorials Point**](http://www.tutorialspoint.com/design_pattern)
Book:
- [**Head First Design Patterns**](http://it-ebooks.info/book/252/)
- [**Design Patterns: Elements of Reusable Object-Oriented Software**](http://www.uml.org.cn/c%2B%2B/pdf/DesignPatterns.pdf)
All rights reserved