Có vi phạm nguyên tắc trong lập trình OOP khi làm những điều này?

Không biết mọi người thường để các method kiểm tra validation như thế nào? Tui cũng đã thử ném hết vào một class nhưng như vậy thì không hề giống một đối tượng tí nào. Ví dụ:

public class Validation {
    public static boolean isValidDefend(Integer defend) {
        return defend != null && defend >= Fighter.MIN_DEFEND && defend <= Fighter.MAX_DEFEND;
    }
    
    public static boolean isValidDamage(Integer damage) {
        return damage != null && damage > Fighter.MIN_DAMAGE && damage <= Fighter.MAX_DAMAGE;
    }
    
    public static boolean isValidName(String name) {
        return !name.isEmpty() && !name.chars().allMatch(Character::isWhitespace);
    }
}

Thêm một câu hỏi là các biến hằng tui nên để static hay là dùng getter để lấy giá trị, và nếu đối tượng có nhiều hằng như vậy thì có nên tách ra làm một đối tượng khác, TheRules chẳng hạn.

public class Fighter {
    public static final int MAX_HEALTH = 150;
    public static final int MAX_MANA   = 100;
    public static final int BEGIN_MANA = 0;
    public static final int MAX_DAMAGE = 10;
    public static final int MIN_DAMAGE = 1;
    public static final int MAX_DEFEND = 10;
    public static final int MIN_DEFEND = 0;
//....
}

Không biết nếu làm những điều trên thì có vi phạm nguyên tắc không? Mong được góp ý.

Khi bạn đang dùng một ngôn ngữ OOP thì không phải lúc nào cũng phải thiết kế hoàn toàn OOP.
Không phải cái gì cũng phải nằm trong 1 object, cái gì cũng phải thông qua property…
Hãy sử dụng cho phù hợp để ít nhất là cảm thấy thoải mái. Đừng tự trói buộc vào những quy tắc mà có khi nó làm cho mình thấy khổ sở, vất vả.
Ý kiến cá nhân.

9 Likes

Hi there,
Tớ nghĩ cậu đúng khi nghi ngờ điều này. Câu trả lời cho cậu là: có, design của cậu có phá hỏng 1 số tính chất của OO design :smile:

Design này có vấn đề gì?

Ở class Validation, tất cả các method của cậu đều là public static method. Static method như cậu biết, là hành vi không gắn liền với bất cứ object nào. Hiển nhiên, việc này phá hỏng điều quan trọng nhất của OO design: hướng về đối tượng :wink:

Ở class Fighter, cậu cũng có 1 loạt hằng số, nhưng nó cũng public static nốt. Điều này phá hỏng tính đóng gói (encapsulation), khi những object khác có thể tùy ý truy cập vào những thông tin riêng tư của Fighter. Thử tưởng tượng điều này xảy ra trong đời thường, hẳn các object khác sẽ bị bế hết lên đồn :sweat_smile:

Làm thế nào để sửa design trên theo OOP

Ở class Validation, cậu có thể áp dụng tính chất tổng quát hoá, design 1 flow chuẩn cho việc validate, và áp dụng tính đa hình để định nghĩa riêng cách validate cho từng bài toán cụ thể.

public interface Validation<T> {
  /**
  * Validate against a particular instance, and throw ValidationException when it is invalid.
  *
  */
  void validate(T instance) throws ValidationException;
}

//...
public class ValidDefendValidator implements Validation<Integer> {
  // Overide the validate method here
}

Ở bên class Fighter, cậu nên để hằng số private, và đưa ra getter nếu cần, hoặc tách toàn bộ phần hằng số này ra 1 class Configuration nào đó, và cung cấp method getConfig với tham số configName nào đó.
Khi nào cậu cần thông tin config “MAX_HEALTH”, cậu chỉ cần lịch sự hỏi object Configuration:

Configuration.getInstance().getConfig("MAX_HEALTH");

Khi đó, Configuration sẽ đưa cho cậu thông tin cậu cần :smile: Điểm khác biệt nằm ở thái độ của một quý ông, khi cậu không phải xông vào nhà Fighter và lấy đi bí mật thầm-kín-nhưng-bị-public của nó, mà lịch sự hỏi Configuration xem cậu ấy có thể giúp không.

Có nên sửa design trên theo OOP không?

Hì hì.
Như cậu thấy ở trên, sửa design theo OOP trông khá nice, nhưng sẽ khá tốn công. Vậy nên, cậu cần phải thực sự cân nhắc điều này: cậu cần 1 design trông đơn giản, và hiệu quả, hay cậu cần 1 design chặt chẽ, đúng, nhưng cực kỳ tốn công để tạo ra và maintain?
Như Lão Hạc có đề cập ở trên, đó thực ra là 1 quan điểm rất thực tế, và tớ không thể đồng ý hơn :smile:.
Cá nhân tớ không có vấn đề gì với class Validation của cậu. Nó đơn giản và hiệu quả (miễn là cậu không để static method ở các chỗ khác, hoặc class này nằm trong framework mà bên cậu đang sử dụng, thứ nên được design 1 cách trừu tượng :sweat_smile:). Class Fighter tớ cũng không có vấn đề gì, trừ khi có object khác đọc thông tin MAX_HEALTH thật :sweat_smile:
Vậy nên, cậu sẽ nên là người quyết định, tùy vào tình huống mà có design phù hợp.

Hope it helps!

7 Likes

Ap dụng strategy pattern.

7 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?