Author: chungnt6

  • [DesignPattern] Simple Factory Pattern

    [DesignPattern] Simple Factory Pattern

    Background

    Hầu hết anh em developer đều đã nghe qua về Design Pattern

    Tuy nhiên mình thấy còn nhiều người (gồm cả mình) đều không có kinh nghiêm áp dụng nó.

    Nên mình lập topic về design pattern để mọi người có thể chia sẻ kinh nghiệm và cách áp dụng nó trong các bài toán cụ thể.

    Vậy đầu tiên chúng ta phải hiểu design pattern là gì?

    • Theo mình hiểu design pattern đơn giản là các giải pháp mẫu tối ưu cho từng tình huống cụ thể trong lập trình OOP.

    Taị sao lại sử dụng design pattern?

    Một thực tế là mình nghe rất nhiều câu như refactor đi (dm code như shit, fucking coding …),đập hết đi xây lại.

    Tại sao chúng ta lại muốn như thế?

    Vì hầu hết các source code ban đầu đều rất khó maintain và mở rộng, nên khi có một yêu cầu mới hay một bug,

    anh em lại cặm cụi sửa code, sửa bug này lại sinh ra bug khác nên effort để giải quyết một vấn đề rất tốn kém.

    Do đó nếu mình không chỉ "code để chạy được" mà suy nghĩ, áp dụng các design pattern trươc khi viết ra

    sẽ rút ngắn phần lớn thời gian development và maintain.

    Sau đây mình xin trình bầy một số design pattern mà mình đã đọc qua.

    Đầu tiên mình xin tập trung vào một loại pattern mà chắc anh em ai cũng nghe qua, đó là Factory Pattern

    Factory Pattern có 3 loại: Simple factory, Factory method và Abstract Factory

    Bài lần này mình sẽ trình bày về Simple Factory Pattern

    Simple Factory Pattern

    Bài toán

    Nào chúng ta hãy làm quen với Simple Factory Pattern với một ví dụ như sau:

    Giả sử bạn đang viết chương trình đặt hàng và ship hàng cho một cửa hàng Pizza

    Quá trình đặt hàng một chiếc Pizza sẽ qua các công đoạn như chuẩn bị (prepare), nướng (bake) và đóng hộp (box)

    Xử lý để chạy được & vấn đề

    Chương trình có thể được viết như sau

    Class PizzaStore {
      public Pizza orderPizza() {
        Pizza pizza = new Pizza();
        pizza.prepare();
        pizza.bake();
        pizza.box();
        return pizza;
      }
      public void shipPizza() {
        Pizza pizza = new Pizza();
        pizza.ship();
       }
    }
    

    OK như vậy là có sample về chương trình orderPizza và shipPizza.

    Nhưng chủ cửa hàng lại muốn có nhiều món pizza cơ mà.

    Ví du: Pizza gà (ChickenPizza), Pizza phô mai(CheesePizza)

    Bạn nên làm thế nào ???

    Dễ mà tạo một lớp cha Pizza và create 2 lớp con là ChickenPizza và CheesePizza

    Sau đó add thêm parameter type cho orderPizza và shipPizza

    Class PizzaStore {
      public Pizza orderPizza(String type) {
        Pizza pizza;
        if ("chicken".equals(type) {
          pizza = new ChickenPizza();
        } esle ("cheese".equals(type) {
          pizza = new ChickenPizza();
        }
        pizza.prepare();
        pizza.bake();
        pizza.box();
        return pizza;
      }
      public void shipPizza(String type) {
        Pizza pizza;
        if ("chicken".equals(type) {
          pizza = new ChickenPizza();
        } esle if ("cheese".equals(type) {
          pizza = new ChickenPizza();
        }
        pizza.ship();
      }
    }
    

    OK các bạn thấy thế nào, chương trình chạy ngon không có lỗi gì luôn :D.

    Một tuần sau cửa hàng thấy cần thêm món Pizza hải sản (SeaFoodPizza) để tăng thêm khách hàng

    Bạn sẽ vào sửa method orderPizza???

    Class PizzaStore {
      public Pizza orderPizza(String type) {
        Pizza pizza;
        if ("chicken".equals(type) {
          pizza = new ChickenPizza();
        } esle if ("cheese".equals(type) {
          pizza = new ChickenPizza();
        } else if ("seafood".equals(type) {
          pizza = new SeaFoodPizza();
        }
        pizza.prepare();
        pizza.bake();
        pizza.box();
      }
      public void shipPizza(String type) {
        Pizza pizza;
        if ("chicken".equals(type) {
          pizza = new ChickenPizza();
        } esle if ("cheese".equals(type) {
          pizza = new ChickenPizza();
        }
        pizza.ship();
      }
    }
    

    Cơn ác mộng mới chỉ bắt đầu :)). Đấy là mình chỉ liệt kê 2 chức năng cơ bản, điều gì sẽ xảy ra nếu còn rất nhiều chức năng khác cần lấy thông tin pizza theo từng loại

    Ví du: Lấy thông tin giá, tên, … của từng loại Pizza

    Bạn sẽ phải hì hục sửa code tất cả cả các method đấy nếu cửa hàng tạo thêm một loại Pizza.

    Vâng bạn sẽ vẫn cố gắng sửa để nó có thể chạy được nhưng bạn sẽ tốn rất nhiều effort để làm việc này nếu có hàng chục method cần sửa.

    Bạn cũng lo lắng mình có thể quên xử lý ở một method nào đấy,…

    -> Giờ bạn đã sợ maintain chưa

    Áp dụng Simple Factory Pattern vào bài toán

    Quá nhiều điều để lo lắng chúng ta phải refactor thôi.

    Đầu tiên chắc các bạn cũng thấy luôn, chúng ta cần đóng gói việc khởi tạo object bên dưới

    if ("chicken".equals(type) {
      pizza = new ChickenPizza();
    } esle if ("cheese".equals(type) {
      pizza = new ChickenPizza();
    } else if ("seafood".equals(type) {
      pizza = new SeaFoodPizza();
    }
    

    Chuyển đoạn code trên sang một class factory

    Class SimplePizzaFactory {
      public Pizza createPizza(type) {
        Pizza pizza;
        if ("chicken".equals(type) {
          pizza = new ChickenPizza();
        } esle if ("cheese".equals(type) {
          pizza = new ChickenPizza();
        } else if ("seafood".equals(type) {
          pizza = new SeaFoodPizza();
        }
        return pizza;
     }
    }
    

    Tiếp theo chúng ta sẽ sử dụng SimplePizzaFactory để tạo trong PizzaStore để tạo các object

    Class PizzaStore {
      SimplePizzaFactory mFactory;
    
      public PizzaStore (SimplePizzaFactory factory) {
        mFactory = factory;
      }
    
      public Pizza orderPizza(String type) {
        Pizza pizza = mFactory.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.box();
      }
      public void shipPizza(String type) {
        Pizza pizza = mFactory.createPizza(type);
        pizza.ship();
      }
    }
    

    Bạn thấy công việc đơn giản hơn chưa, việc khởi tạo object cần thiết được xử lý trong Factory

    Như vậy chúng ta không cần phải lo lắng sửa code ở từng method như orderPizzahay shipPizza, … nữa 🙂

    Conlution

    Đây chỉ là một ví dụ rất cơ bản về Design Pattern giúp mọi người dễ hình dung và tiếp cận

    Chúng ta còn rất nhiều bài toán phức tạp khác cần Design Pattern để xử lý

    Quan trọng mọi người hiểu được việc "code để chạy" có thể nhanh trong thời điểm đấy

    Tuy nhiên việc mọi người phải rework để phát triển nó sẽ tốn gấp đôi gấp mười lần effort nếu mọi người có thể làm Design cẩn thận từ đầu

    Do đó việc hiểu các Design pattern hỗ trợ rất tốt cho mọi người trong việc triển khai các bài toán cụ thể

    Hy vọng bài này giúp mọi người hiểu được cơ bản Design Pattern là gì và tầm quan trọng của nó trong software