Đây là bài viết thứ 2 của tôi thực hiện mô phỏng tính nhẩm một phép nhân. Bài viết trước là Mô phỏng phương pháp tính nhanh nhân 2 số có cùng hàng chục. Trước khi đi vào chạy mô phỏng phép tính nhân 2 số bé hơn và gần bằng 100 tôi muốn chia sẻ với các bạn về design pattern được sử dụng trong mô phỏng của cả 2 bài viết.

Design pattern ở được sử dụng là Strategy pattern (Mô hình chiến lược). 

Strategy pattern

Strategy pattern định nghĩa một tập các thuật toán được đóng gói và tùy theo từng trường hợp được sử dụng mà client sẽ sử dụng thuật toán cần thiết

Các class và objects được định nghĩa trong pattern

Strategy: Định nghĩa phương thức mà các thuật toán cần phải có.

ConcreteStrategy: Kế thừa tới Strategy và viết lại phương thức cho thuật toán

Context: Tham chiếu tới Strategy và gọi phương thức của Strategy

Tôi thì hay quen gọi pattern này là Hero Pattern vì tôi liên tưởng tới một siêu anh hùng lúc thì cầm búa, lúc cầm chùy, lúc cầm giáo, súng mà đánh tới tấp vào quái vật. Kiểu như này

public abstract class Weapon
{
    public abstract int GetDamage();
}

public class Gun : Weapon
{
    public override int GetDamage()
    {
        return 10000;
    }
}

public class Sword : Weapon
{
    public override int GetDamage()
    {
        return 200;
    } 
}

public class Hero
{
    public Weapon Weapon { private set; get; }
    public void UseWeapon<TWeapon>() where TWeapon: Weapon, new()
    {
        Weapon = new TWeapon();
    }
    
    public void Attack()
    {
        Weapon.GetDamage();
    }
}

var son20Hero = new Hero();

// Cầm kiếm mà đánh
son20Hero.UseWeapon<Sword>();
son20Hero.Attack();

// Cầm súng mà bắn
son20Hero.UseWeapon<Gun>();
son20Hero.Attack();

Vậy cái Hero Pattern này áp dụng để viết 2 mô phỏng phép nhân như thế nào laugh. Nhưng chạy demo trước đã, vì chủ đề bài viết này là mô phỏng phép tính nhân 2 số bé hơn và gần bằng 100 cơ mà smiley

Tạo ngẫu nhiên 2 số bé hơn và gần bằng 100
  • ?
  • ?
  • x
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • -
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • -
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • -
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • x
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • ?
  • +
  • ?
  • ?
  • ?
  • ?
  • ?

Các bạn có thể xem lại Mô phỏng phương pháp tính nhanh nhân 2 số có cùng hàng chục.

Như các bạn thấy, 2 mô phỏng là giống nhau, có cái khác nhau ở đây là phương pháp, thuật toán nhân 2 số khác nhau. Vì thế trong trường hợp này sử dụng Hero pattern là hoàn toàn hợp lý.

Cụ thể các class như sau:

function MathX()
{
    // Định nghĩa phương thức tạo 2 số cần thực hiện nhân
    this.onCreateNumber = function () { };
    
    // Định nghĩa phương thức tạo kịch bản của phép nhân
    this.onCreateScripts = function (scripts) { };
    
    // ......
}

Đây chính là Strategy. các bạn có thể xem cụ thể MathX.js tại đây

function PageMathX()
{
    this.mathX; // Tham chiếu tới Strategy MathX
    this.start = function()
    {
        // sẽ thực hiện gọi phương thức onCreateNumber để tạo 2 số cần nhân
        // sẽ thực hiện gọi phương thức onCreateScripts để lấy kịch bản nhân
    }
}

Đây chính là Context. Cũng được khai báo trong file MathX.js. Tại PageMathX tôi đã bao gồm khai báo toàn bộ sự kiện trên giao diện như sự kiện bấm tạo số, bấm thực hiện phép tính và trượt chọn tốc độ

Đã xong, cuối cùng chúng ta chỉ việc viết thuật toán của phép nhân, khởi tạo ConcreteStrategy và gán vào this.mathX.

var ABxCD = function ()
{
    $.extend(this, new MathX());
    
    this.onCreateNumber = function ()
    {
        this.number1 = Core.random(100);
        while (this.number1 < 80) this.number1 = Core.random(100);

        this.number2 = Core.random(100);
        while (this.number2 < 80) this.number2 = Core.random(100);

        n1 = 100 - this.number1; lengthN1 = (n1 + "").length - 1;
        n2 = 100 - this.number2; lengthN2 = (n2 + "").length - 1;

        number1_n2 = this.number1 - n2;
        lengthNumber1_n2 = (number1_n2 + "").length;

        n1xn2 = n1 * n2;
        lengthN1xN2 = (n1xn2 + "").length;

        if (n1xn2 >= 100)
        {
            f_n1xn2 = parseInt((n1xn2 + "").charAt(0));
            length_f_n1xn2 = (f_n1xn2 + "").length;

            number1_n2_plus_f = number1_n2 + f_n1xn2;
            length_number1_n2_plus_f = (number1_n2_plus_f + "").length;

            n1xn2_b = n1xn2 - f_n1xn2 * 100;
        }
    }
    this.onCreateScripts = function (scripts)
    {
        scripts.push(this.createScript0());
        scripts.push(this.createScript01());
        scripts.push(this.createScript1());
        scripts.push(this.createScript2());
        scripts.push(this.createScript3());
        scripts.push(this.createScript31());
        scripts.push(this.createScript4());
        scripts.push(this.createScript5());
        scripts.push(this.createScript6());
        scripts.push(this.createScript61());
        scripts.push(this.createScript7());
        scripts.push(this.createScript8());
        scripts.push(this.createScript9());
        scripts.push(this.createScript10());
        scripts.push(this.createScript101());
        scripts.push(this.createScript11());
        scripts.push(this.createScript12());
        if (n1xn2 >= 100)
        {
            scripts.push(this.createScript14());
            scripts.push(this.createScript141());
            scripts.push(this.createScript15());
            scripts.push(this.createScript16());
            scripts.push(this.createScript17());
            scripts.push(this.createScript18());
            return;
        }
        scripts.push(this.createScript13());
    }
}

ABxCD ở đây chính là một ConcreteStrategy. Các bạn có thể xem chi tiết tại đây

Và cuối cùng thực hiện khởi tạo Context PageMathX và gán một khởi tạo ABxCD cho thuộc tính this.mathX

var pageMathX = new PageMathX();
pageMathX.mathX = new ABxCD();
pageMathX.start();

Như vậy với việc sử dụng Strategy (Hero) pattern. Tôi có thể xây dựng một loạt các mô phỏng phép nhân trong thời gian tới. Mà tôi chỉ việc xử lý về thuật toán, các bước mô phỏng mà ko cần quan tâm tới giao diện nữa (Giao diện lúc này đã có đủ chức năng bấm tạo số, bấm thực hiện phép tính, thanh trượt chọn tốc độ).

Nếu biết sử dụng design pattern các bạn sẽ là một coder thực chiến thực thụ

Sơn 20