Chào các bạn, trong bài viết trước chúng ta đã tìm hiểu về Factory Method Pattern. Trong bài này chúng ta tiếp tục tìm hiểu một Pattern khác trong nhóm Creational Design Pattern là Abstract Factory Design Pattern.
Abstact Factory Pattern
Abstract Factory pattern là một trong những Creational pattern. Nó là pattern tạo ra một Super-factory dùng để tạo ra các Factory khác, chúng ta có thể hiểu là Factory của các Factory. Qua đó chúng ta có thể coi Abstract Factory Pattern là một Pattern cấp cao hơn so với Factory Method Pattern.
Để dễ hình dung hơn, hãy tưởng tượng Abstract Factory như là một nhà máy lớn chứa nhiều nhà máy nhỏ, trong các nhà máy đó có những xưởng sản xuất, các xưởng đó tạo ra những sản phẩm khác nhau.
Cài đặt Abstact Factory Pattern
Abstract Factory Pattern bao gồm năm thành phần cơ bản là: Abstract Factory, Concrete Factory, Abstract Product, Concrete Product và Client.
- AbstractFactory: Khai báo dạng interface hoặc abstract class chứa các phương thức để tạo ra các đối tượng abstract.
- ConcreteFactory: Xây dựng, cài đặt các phương thức tạo các đối tượng cụ thể.
- AbstractProduct: Khai báo dạng interface hoặc abstract class để định nghĩa đối tượng abstract.
- Product: Cài đặt của các đối tượng cụ thể, cài đặt các phương thức được quy định tại AbstractProduct.
- Client: là đối tượng sử dụng AbstractFactory và các AbstractProduct.
Hình minh họa cách triển khai Abstract Factory Pattern
Ví dụ demo
Ví dụ: Một công ty chuyên sản xuất xe (Vehical) bao gồm 2 loại phương tiện: xe hơi (Car) và xe máy (Motobike).
Car bao gồm 2 loại xe: familiar car và luxury car.
Motobike bao gồm 2 loại xe: sport motobike và cruise motobike
Vì quy trình sản xuất cho từng loại phương tiện là khác nhau. Nên công ty tách ra là nhà máy (Factory): 1 cho sản xuất xe ô tô (CarFactory), 1 cho sản xuất xe máy (BicycleFactory). Khi khách hàng cần mua loại xe nào thì khách hàng (Client) chỉ cần đến cửa hàng để mua (VehicleFactory). Khi đó ứng với từng phương tiện sẽ được chuyển về phân xưởng tương ứng để sản xuất
Tiến hành cài đặt
Trong ví dụ này chúng ta có những thực thể sau
Vehicle : Interface mà tất cả các đối tượng trong trong các factory phải triển khai
- Motorbike : Interface dành cho 2 loại xe motobike là : sport và cruise (Concrete product)
- Car : Interface dành cho 2 loại xe car là : familiar và luxury (Concrete product)
VehicleFactory : Đây là interface (Abstract Factory) trả về các factory implement
VehicleFactory
interfaceMotorbike Factory : Một factory implement interface
VehicleFactory
và trả lại phương tiện implement 2 interface làVehicle
vàMotorbike
Car Factory : Một factory implement interface
VehicleFactory
và trả lại phương tiện implement 2 interface làVehicle
vàCar
Để rõ ràng trong quá trình triển khai, chúng ta sẽ tách từng thực thể thành các file khác nhau. Chúng ta sẽ bắt đầu với interface Vehicle
trong file vehicle.go
// file vehicle.go
package vehicle
type Vehicle interface {
GetWheels() int
GetSeats() int
}
Interface car và motobike trong car.go
và motobike.go
// car.go
package vehicle
type Car interface {
GetDoors() int
}
// motobile.go
package vehicle
type Motorbike interface {
GetType() int
}
Tiếp theo chúng ta cần định nghĩa interface mà mỗi factory cần phải implement trong file vehicle_factory.go
// vehicle_factory.go
package vehicle
type VehicleFactory interface {
GetVehicle(v int) (Vehicle, error)
}
OK, tiếp theo chúng ta sẽ khai báo car factory. CarFactory phải implement VehicleFactory
interface đã được định nghĩa trước đó và trả về Vehicles
instances
// car_factory.go
package vehicle
import (
"errors"
"fmt"
)
const (
LuxuryCarType = 1
FamiliarCarType = 2
)
type CarFactory struct{}
func (c *CarFactory) GetVehicle(v int) (Vehicle, error) {
switch v {
case LuxuryCarType:
return new(LuxuryCar), nil
case FamiliarCarType:
return new(FamiliarCar), nil
default:
return nil, errors.New(fmt.Sprintf("Vehicle of type %d not recognized\n", v))
}
}
Ở đây chúng ta có 2 loại xe : luxury car và familiar car. Cho nên CarFactory cần phải trả về đối tượng car implement 2 interface là : Vehicle
và Car
, vì vậy chúng ta cần tạo ra 2 concrete product
// luxury_car.go
package vehicle
type FamiliarCar struct{}
func (l *FamiliarCar) GetDoors() int {
return 5
}
func (l *FamiliarCar) GetWheels() int {
return 4
}
func (l *FamiliarCar) GetSeats() int {
return 5
}
// familiar_car.go
package vehicle
type LuxuryCar struct{}
func (l *LuxuryCar) GetDoors() int {
return 6
}
func (l *LuxuryCar) GetWheels() int {
return 7
}
func (l *LuxuryCar) GetSeats() int {
return 8
}
Tương tự như car, bây giờ chúng ta cũng cần tạo ra motobike factory và implement VehicleFactory
interface
// motobike_factory.go
package vehicle
import (
"errors"
"fmt"
)
const (
SportMotorbikeType = 1
CruiseMotorbikeType = 2
)
type MotorbikeFactory struct{}
func (m *MotorbikeFactory) GetVehicle(v int) (Vehicle, error) {
switch v {
case SportMotorbikeType:
return new(SportMotorbike), nil
case CruiseMotorbikeType:
return new(CruiseMotorbike), nil
default:
return nil, errors.New(fmt.Sprintf("Vehicle of type %d not recognized\n", v))
}
}
Đối với phương tiện là motobike chúng ta xác định có 2 loại xe : sport motobike và cruise motobike. Vậy nên chúng ta cần tạo ra 2 concrete product để implement 2 interface là : Vehicle
và Car
// sport_motobike.go
package vehicle
type SportMotorbike struct{}
func (s *SportMotorbike) GetWheels() int {
return 2
}
func (s *SportMotorbike) GetSeats() int {
return 1
}
func (s *SportMotorbike) GetType() int {
return SportMotorbikeType
}
// cruise_motobike.go
package vehicle
type CruiseMotorbike struct{}
func (c *CruiseMotorbike) GetWheels() int {
return 2
}
func (c *CruiseMotorbike) GetSeats() int {
return 2
}
func (c *CruiseMotorbike) GetType() int {
return CruiseMotorbikeType
}
Để hoàn thành thì chúng ta cần chỉnh lại abstract factory lúc đầu trong file vehicle_factory.go
để nó tạo và trả về sub-factory tương ứng
// vehicle_factory.go
package vehicle
import (
"errors"
"fmt"
)
type VehicleFactory interface {
GetVehicle(v int) (Vehicle, error)
}
const (
CarFactoryType = 1
MotorbikeFactoryType = 2
)
func GetVehicleFactory(f int) (VehicleFactory, error) {
switch f {
case CarFactoryType:
return new(CarFactory), nil
case MotorbikeFactoryType:
return new(MotorbikeFactory), nil
default:
return nil, errors.New(fmt.Sprintf("Factory with id %d not recognized\n", f))
}
}
OK, bây giờ trong file main.go
(client) chúng ta gọi factory và sản xuất ra các loại phương tiện tương ứng
package main
import (
"fmt"
v "abstract-factory-pattern/vehicle"
)
func main() {
// Car Factory
carFactory, _ := v.GetVehicleFactory(v.CarFactoryType)
// Luxury car
luxuryCar, _ := carFactory.GetVehicle(v.LuxuryCarType)
fmt.Println("Luxury car")
printDetail(luxuryCar)
// Familiar car
familiarCar, _ := carFactory.GetVehicle(v.FamiliarCarType)
fmt.Println("Familiar car")
printDetail(familiarCar)
// Motobike Factory
motobikeFactory, _ := v.GetVehicleFactory(v.MotorbikeFactoryType)
// Sport Motobike
sportMotobike, _ := motobikeFactory.GetVehicle(v.SportMotorbikeType)
fmt.Println("Sport Motobike")
printDetail(sportMotobike)
// Cruise Motobike
cruiseMotobike, _ := motobikeFactory.GetVehicle(v.CruiseMotorbikeType)
fmt.Println("Cruise Motobike")
printDetail(cruiseMotobike)
}
func printDetail(v v.Vehicle) {
fmt.Printf("Seats : %d\n", v.GetSeats())
fmt.Printf("Wheels : %d\n\n", v.GetWheels())
}
Kết quả
Luxury car
Seats : 8
Wheels : 7
Familiar car
Seats : 5
Wheels : 4
Sport Motobike
Seats : 1
Wheels : 2
Cruise Motobike
Seats : 2
Wheels : 2
Ưu và nhược điểm của Abstract Factory Pattern
Ưu điểm
- Abstract Factory Pattern giúp đảm bảo rằng các product mà chúng ta nhận được từ một factory đều tương thích với nhau
- Abstract Factory Pattern giúp hạn chế sự phụ thuộc giữa creator và concrete products.
- Abstract Factory Pattern giúp gom các đoạn code tạo ra product vào một nơi trong chương trình, nhờ đó giúp dễ theo dõi và thao tác.
- Với Abstract Factory Pattern, chúng ta có thể thoải mái thêm nhiều loại product mới vào chương trình mà không làm thay đổi các đoạn code nền tảng đã có trước đó.
Nhược điểm
- Code có thể trở nên nhiều hơn và phức tạp hơn do đòi hỏi phải sử dụng nhiều class mới có thể cài đặt được pattern này.
Bình luận