Thứ Sáu, 3 tháng 2, 2012

OOP - Bài 6: Thẻ tín dụng (Credit Card)


Thiết kế chương trình hướng đối tượng

Center of Excellence

Bài 6
Thẻ Tín Dụng (Credit Card)


Điều thường hằng duy nhất, đó là sự thay đổi
-- Heraclitus


I. Bài toán

Để có thể cấp thẻ tín dụng (credit card) cho khách hàng, ngân hàng cần kiểm tra hai thông tin: lương hàng năm (annual salary) và mức độ tín nhiệm (credit rating). Hãy phát triển code nhận vào từ keyboard annual salary và credit rating của một khách hàng, trong đó annual salary là một số dương và credit rating là một số nguyên từ 1 (rất tệ) đến 10 (rất được tín nhiệm), sau đó code sẽ cho biết khách hàng có thể được cấp credit card hay không. Biết rằng khách hàng cần thỏa mãn hai điều kiện: annual salary tối thiểu là 20.000 USD và credit rating tối thiểu bằng 7.

Bạn không phải phát triển phần UI, nhưng để hiểu rõ hơn yêu cầu bài toán, bạn có thể tham khảo một UI mẫu dưới đây.

Hình 1

II. Giải pháp

Tương tự như bài trước, bài này yêu cầu ta thực hiện việc nhập data rồi tính toán.

  1. Nhập annual salary (phải là số nguyên dương)
    • Input: từ keyboard
    • Output: annual salary
  2. Nhập credit rating (phải từ 1 đến 10)
    • Input: từ keyboard
    • Output: credit rating
  3. Kiểm tra khách hàng có được cấp credit card hay không
    • Input: annual salary, credit rating
    • Output: có (true) hoặc không (false)

1. Nhập annual salary

1.1. Thiết kế sơ bộ

Theo kinh nghiệm thiết kế ở bài trước, ta có thể có ba classes: Input class phục vụ việc nhập data, một class dùng để tính toán (tên class sẽ được quyết định sau, phụ thuộc vào yêu cầu tính toán), và Main class để thực hiện việc tích hợp nhằm tạo ra một chương trình hoàn chỉnh.
Hình 2

1.2. Test cases


readAnnualSalary()
No
input từ keyboard
annualSalary?
1
30_000
30_000
2
20_000
20_000
3
10_000
10_000
4
0
không chấp nhận



1.3. Phát triển method

  • Project: CreditCard

Biết rằng bài này và bài trước đều có Input class, ta cần xem xét khả năng tái dụng (reuse) Input class của bài trước cho bài này được hay không.

Hình 3

Nhận xét rằng readAnnualSalaryGui() rất giống với readPlayersGui() (code duplication), vì vậy ta cần refactor chúng. Hai methods này có điểm chung là yêu cầu user nhập một số nguyên dương, vì vậy ta có thể sát nhập chúng thành một method, gọi là readPositiveIntGui(). Điểm khác biệt của hai methods là nội dung lời nhắc (prompt), nên ta bổ sung prompt parameter cho method mới. Sau khi đã hoàn thành việc xây dựng và kiểm thử method mới, ta có thể loại bỏ hai methods cũ ra khỏi class.

Hình 4

Hình 5


2. Nhập credit rating

2.1. Thiết kế sơ bộ

Hình 6

Từ kinh nghiệm của phần trước, ta có thể thử sát nhập hai methods readPlayersPerTeamGui()readCreditRatingGui() thành readIntGui() với nhiều hơn một parameter, đó là prompt.

Hình 7


2.2. Test cases


readIntGui()
No
lowerBound
upperBound
input từ keyboard
output?
1
9
15
8
không chấp nhận
2
9
15
9
9
3
9
15
10
10
4
9
15
15
15
5
9
15
16
không chấp nhận
6
1
10
0
không chấp nhận
7
1
10
1
1
8
1
10
5
5
9
1
10
10
10
10
1
10
11
không chấp nhận



2.3. Phát triển method

Hình 8

Hình 9


3. Kiểm tra khách hàng có được cấp credit card hay không

3.1. Thiết kế sơ bộ

Hình 10


3.2. Test cases


qualify()
No
annualSalary
creditRating
qualify?
1
10_000
1
false
2
10_000
3
false
3
10_000
7
false
4
10_000
8
false
5
10_000
10
false
6
20_000
1
false
7
20_000
3
false
8
20_000
7
true
9
20_000
8
true
10
20_000
10
true
11
30_000
1
false
12
30_000
3
false
13
30_000
7
true
14
30_000
8
true
15
30_000
10
true



3.3. Phát triển method

CreditCardRequestTest.java

package model;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;

public class CreditCardRequestTest {
    @Test public void qualify(){
        assertFalse(new CreditCardRequest(10_000, 1).qualify());
        assertFalse(new CreditCardRequest(10_000, 3).qualify());
        assertFalse(new CreditCardRequest(10_000, 7).qualify());
        assertFalse(new CreditCardRequest(10_000, 8).qualify());
        assertFalse(new CreditCardRequest(10_000, 10).qualify());
                
        assertFalse(new CreditCardRequest(20_000, 1).qualify());
        assertFalse(new CreditCardRequest(20_000, 3).qualify());
        assertTrue(new CreditCardRequest(20_000, 7).qualify());
        assertTrue(new CreditCardRequest(20_000, 8).qualify());
        assertTrue(new CreditCardRequest(20_000, 10).qualify());
                
        assertFalse(new CreditCardRequest(30_000, 1).qualify());
        assertFalse(new CreditCardRequest(30_000, 3).qualify());
        assertTrue(new CreditCardRequest(30_000, 7).qualify());
        assertTrue(new CreditCardRequest(30_000, 8).qualify());
        assertTrue(new CreditCardRequest(30_000, 10).qualify());
    }
}

CreditCardRequest.java

package model;

public class CreditCardRequest {
    private final int annualSalary;
    private final int creditRating;

    public CreditCardRequest(int annualSalary, int creditRating) {
        this.annualSalary = annualSalary;
        this.creditRating = creditRating;
    }
    
    public boolean qualify() {
        return annualSalary >= 20_000 && creditRating >= 7;
    }
}


4. Tích hợp

package controller;

import javax.swing.JOptionPane;
import model.CreditCardRequest;
import view.Input;

public class Main {
    private Main() {
        throw new RuntimeException(this.getClass() +
                " is a noninstantiable utility class");
    }
    
    public static void main(String[] args) {
        int annualSalary = Input.readPositiveIntGui("Annual salary: ");
        int creditRating = Input.readIntGui("Credit rating: ", 1, 10);
        
        boolean qualified =
                new CreditCardRequest(annualSalary, creditRating).qualify();
        
        if (qualified)
            JOptionPane.showMessageDialog(null, "Qualified");
        else
            JOptionPane.showMessageDialog(null, "Unqualified",
                    null, JOptionPane.ERROR_MESSAGE);
    }
}


III. Tổng kết

Bài này đã trình bày việc tái dụng code và thiết kế có sẵn. Đứng trước một vấn đề mới, nếu thấy nó có dáng dấp tương tự như những vấn đề đã từng gặp trước đây, ta nên thử tìm cách tái dụng (reuse). Khi reuse, có thể cần phải đổi tên và thêm bớt tham số cho phù hợp với tình hình mới.


V. Tài liệu tham khảo

  1. Gaddis T. (2010) Starting Out with Java: From Control Structures Through Objects (4th edition), Pearson Education, Boston. Chương 5.


V. Bài tập

  • Trong Input class, hãy chuyển readPlayersPerTeam(lowerBound, upperBound) thành readInt(lowerBound, upperBound) và phát triển thêm readPositiveInt(). Hai methods này dùng console để nhập data.
  • Hãy thay đổi Main class để dùng hai methods trên.
  • Cần đảm bảo rằng cả hai chương trình của bài này và bài trước đều chạy tốt sau khi thực hiện những thay đổi trên.

Không có nhận xét nào:

Đăng nhận xét