Telescoping Constructor pattern trong Java

Trong bài viết này chúng ta sẽ cùng nhau tìm hiểu về Telescoping Contructor pattern và cách triển khai nó bằng Java.

Khi nào sử dụng Telescoping Constructor

Giả sử chúng ta có một class với rất nhiều thuộc tính và chúng có thể kết hợp với nhau để khởi tạo 1 object theo nhiều cách. Nghĩa là chúng ta có một số tổ hợp các thuộc tính để tạo ra các constructor khác nhau. Nếu làm không khéo sẽ khiến code bị duplicate và khó maintain.

Hay nếu có 1 class với rất nhiều thuộc tính, trong đó có một số thuộc tính là bắt buộc và một số khác là tuỳ chọn. Do đó chúng ta phải tạo ra rất nhiều constructor để thuận tiện cho việc khởi tạo object. Nếu không thì bắt buộc khi khởi tạo object chúng ta phải cung cấp tất cả thuộc tính mặc dù có những thuộc tính tuỳ chọn mà chúng ta không cần thiết, và cũng không biết nên đặt giá trị nào cho các thuộc tính này để hợp lý.

Một lý do nữa là nếu chúng ta có rất nhiều constructor chứa các logic tương tự, nếu làm không tốt thì các constructor này sẽ bị duplicate code. Khi chúng ta thay đổi logic của một thuộc tính, thì chúng ta phải đi sữa tất cả các constructor liên quan dẫn đến chuyện rất khó để maintain mã nguồn.

Telescoping Constructor Pattern được sinh ra để giải quyết các vấn đề trên.

Triển khai Telescoping Constructor

Đầu tiên, mình muốn xin lỗi các bạn vì đã chém gió quá mất. Thật ra thì Telescoping Constructor không phải là một design pattern được công nhận, các bạn có thể xem nó như là một best practice có thể dùng trong dự án.

Chúng ta sẽ lấy ví dụ với Person Entity class chứa rất nhiều thuộc tính. Đầu tiên hãy xem qua ví dụ chưa áp dụng Telescoping Constructor.

public class DirtyPerson {

    private final String name;

    private final String lastName;

    private final int age;

    private final String profession;

    private final List<String> hobbies;

    public DirtyPerson(String name, String lastName) {
        this.name = name;
        this.lastName = lastName;
        this.age = 0;
        this.profession = null;
        this.hobbies = new ArrayList<>();
    }

    public DirtyPerson(String name, String lastName, int age) {
        this.name = name;
        this.lastName = lastName;
        this.age = age;
        this.profession = null;
        this.hobbies = new ArrayList<>();
    }

    public DirtyPerson(String name, String lastName, int age, String profession) {
        this.name = name;
        this.lastName = lastName;
        this.age = age;
        this.profession = profession;
        this.hobbies = new ArrayList<>();
    }

    public DirtyPerson(String name, String lastName, int age, String profession, List<String> hobbies) {
        this.name = name;
        this.lastName = lastName;
        this.age = age;
        this.profession = profession;
        this.hobbies = hobbies == null ? new ArrayList<>() : new ArrayList<>(hobbies);
    }

    public String getName() {
        return name;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    public String getProfession() {
        return profession;
    }

    public List<String> getHobbies() {
        return Collections.unmodifiableList(hobbies);
    }
}

Có tất cả 4 constructor và chúng đều có một số câu lệnh trùng lặp, giờ chúng ta thử áp dụng Telescoping Constructor để xem có giải quyết được gì không.

Trong Telescoping Constructor, một constructor cần sử dụng lại logic của một constructor khác. Việc sử dụng lại một constructor cần đi từ constructor có ít thuộc tính hơn đến constructor có nhiều thuộc tính hơn. Ví dụ constructor chứa 2 tham số đầu vào sẽ gọi constructor có 3 tham số, với một tham số chứa giá trị mặc định mà chúng ta không cần đến.

public class Person {

    private final String name;

    private final String lastName;

    private final int age;

    private final String profession;

    private final List<String> hobbies;

    public Person(String name, String lastName) {
        this(name, lastName, 0);
    }

    public Person(String name, String lastName, int age) {
        this(name, lastName, age, null);
    }

    public Person(String name, String lastName, int age, String profession) {
        this(name, lastName, age, profession, null);
    }

    public Person(String name, String lastName, int age, String profession, List<String> hobbies) {
        this.name = name;
        this.lastName = lastName;
        this.age = age;
        this.profession = profession;
        this.hobbies = hobbies == null ? new ArrayList<>() : new ArrayList<>(hobbies);
    }

    public String getName() {
        return name;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    public String getProfession() {
        return profession;
    }

    public List<String> getHobbies() {
        return Collections.unmodifiableList(hobbies);
    }
}

Chúng ta có thể thấy rằng code đã không còn bị duplicate, các constructor giờ đây có tính tái sử dụng cao. Các thuộc tính tuỳ chọn không cần đến cũng được constructor định nghĩa, chúng ta không cần phải băng khăng đến chúng mà chỉ cần quan tâm đến các thuộc tính cần thiết.

Như vậy chúng ta có thể khởi tạo Person object theo nhiều cách phù hợp với nhu cầu sử dụng.

public class ClientMain {

    public static void main(String[] args) {
        Person person = new Person("name", "lastName");
        System.out.println(person);

        person = new Person("name", "lastName", 20);
        System.out.println(person);

        person = new Person("name", "lastName", 20, "Engineer");
        System.out.println(person);

        person = new Person("name", "lastName", 20, "Engineer", Arrays.asList("Fishing"));
        System.out.println(person);
    }
}

Tóm lược

Trong bài viết này, chúng ta đã tìm hiểu về Telescoping Constructor một best pratice giúp xoá bỏ duplicate code khi viết các constructor cho một class chứa nhiều thuộc tính.

Nguồn tham khảo

https://www.vojtechruzicka.com/avoid-telescoping-constructor-pattern/

http://www.javabyexamples.com/telescoping-constructor-in-java

0 0 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x