Cơ bản về design pattern

Bài viết này mình viết dựa trên một số thứ mình tìm hiểu sau khi học 1 buổi workshop design pattern 😃

Design pattern

Theo định nghĩa tại sourcemaking.com thì:

Là một giải pháp trung được sử dụng nhiều lần để giải quyết một vấn đề trong phát triển phần mềm. Sử dụng lại design pattern sẽ giúp hạn chế các vấn đề phát sinh và giúp code trong sáng, có hệ thống hơn

Các loại design pattern

Có 3 loai chinh đó là :

Creational design pattern

Là các design pattern thiên về khởi tạo các đối tượng

Structural design pattern

Là các design pattern cho phép ta định nghĩa các cách thức quan hệ giữa các đối tượng

Behavioral design pattern

Là các design pattern dùng trong việc thực hiện các hành vi của một đối tượng

Tiếp theo mình sẽ giới thiệu design pattern mình tìm hiểu được

Bridge pattern

Design pattern này được sử dụng khi ta muốn tách rời xử lý của một Class qua một Class khác. Giả sử ta có một lớp mà việc xử lý của nó quá phức tạp, ta muốn tách rời nó qua một lớp khác, ta sẽ chuyển các xử lý đó qua một lớp khác để có thể dễ dàng xử lý

Theo Bridge pattern thì mình đang có Abstraction là lớp Shape. RefinedAbstraction là 2 lớp Triangle và Circle Implementor là lớp Color ConcreteImplementor là lớp lớp GreenColor và BlueColor

Bình thường nếu ta muốn tô màu cho Triangle hoặc Circle, ta có thể nghĩ ngay đến việc implement hàm paint() trong Triangle và Circle như sau

public class Triangle extends Shape{
    public void paint(color) {
        // do something to fill color shape
    }
}

Tuy nhiên việc implement hàm paint() như vậy sẽ khiến ta phải sửa lại code khi có thêm các loại Shape hoặc các Color khác.

Ở đây bridge pattern giúp ta giải quyết được một số vấn đề:

Abstraction và implementaion được định nghĩa một cách độc lập với nhau, giúp ta có thể dễ dàng quản lý, tái sử dụng code ... Mối quan hệ giữa abstraction và implementation được kiểm soát trong run-time code chứ không phải là compile code. Nếu ta để color là một thuộc tính của Shape thì mối quan hệ giữa chúng đã được xác định trong thời gian compile code.

Null object pattern

Mình thấy design pattern này có tư tưởng khá đơn giản. Nếu tìm được object thì trả về object đó, nếu không thì trả về một object khác có cùng interface behavior với real object. Trong ruby thì pattern này được sử dụng để tránh nil erorr khi gọi một hàm trên đối tượng nil

class User
  attr_accessor :credit_card, :subscription

  def charge
    subscription.charge credit_card
  end

  def has_mentoring?
    subscription.has_mentoring?
  end

  def price
    subscription.price
  end

  def subscription
    @subscription ||= NoSubscription.new
  end
end

class NoSubscription
  def charge credit_card
    "No Charge"
  end

  def price
    0
  end

  def has_mentoring?
    false
  end
end

Ở đây ta chú ý function subscription(). Nếu có subscription thì sẽ trả về @subscription, nếu không thì trả về một object NoSubscription mới.

Factory method

Tư tưởng của design pattern này là khởi tạo một đối tượng mà không cần biết trước chính xác lớp của đối tượng đó(creating objects without having to specify the exact class of the object that will be created).

public class Circle implements Shape {
    public void draw() {
        System.out.println("Circle");
    }
}
public class Rectangle implements Shape {
    public void draw() {
        System.out.println("Shape");
    }
}
public interface Shape {
    void draw();
}

public class ShapeFactory {
    public Shape getShape(String shapeType){
        if(shapeType == null){
            return null;
        }
        if(shapeType.equalsIgnoreCase("CIRCLE")){
            return new Circle();

        } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
            return new Rectangle();

        } else if(shapeType.equalsIgnoreCase("SQUARE")){
            return new Square();
        }

        return null;
    }
}

Ở đây ta có thể khởi tạo Rectangle hoặc Circle mà không cần gọi Circle.new(). Đoạn code trong getShape() có if, else vi phạm quy tắc Open/Closed trong SOLID cần refactor lại một chút 😃