CodeGym/Blog Java/Ngẫu nhiên/Trình xây dựng Java

Trình xây dựng Java

Xuất bản trong nhóm
CHÀO! Hôm nay chúng ta sẽ xem xét một chủ đề rất quan trọng liên quan đến các đối tượng của chúng ta. Không cường điệu, chúng tôi có thể nói rằng bạn sẽ sử dụng chủ đề này trong cuộc sống thực hàng ngày! Chúng ta đang nói về Java Constructor. Đây có thể là lần đầu tiên bạn nghe thuật ngữ này, nhưng thực ra bạn đã sử dụng hàm tạo rồi. Bạn chỉ không nhận ra điều đó :) Chúng tôi thuyết phục bản thân về điều này sau.

Các nhà xây dựng trên thế giới là gì và tại sao chúng lại cần thiết?

Hãy xem xét hai ví dụ.
public class Car {

   String model;
   int maxSpeed;

   public static void main(String[] args) {

       Car bugatti = new Car();
       bugatti.model = "Bugatti Veyron";
       bugatti.maxSpeed = 378;

   }
}
Chúng tôi đã tạo ra chiếc ô tô của mình, thiết lập kiểu dáng và tốc độ tối đa của nó. Nhưng đối tượng Car rõ ràng sẽ không có 2 trường trong một dự án thực. Ví dụ, nó có thể có 16 trường!
public class Car {

   String model;// model
   int maxSpeed;// maximum speed
   int wheels;// wheel width
   double engineVolume;// engine volume
   String color;// color
   int productionYear;// production year
   String ownerFirstName;// first name of owner
   String ownerLastName;// last name of owner
   long price;// price
   boolean isNew;// flag indicating whether car is new
   int seatsInTheCar;// number of seats in the car
   String cabinMaterial;// interior material
   boolean insurance;// flag indicating whether car is insured
   String manufacturerCountry;// manufacturer country
   int trunkVolume;// size of the trunk
   int accelerationTo100km;// how long it takes to accelerate to 100 km/h (in seconds)


   public static void main(String[] args) {
       Car bugatti = new Car();

       bugatti.color = "blue";
       bugatti.accelerationTo100km = 3;
       bugatti.engineVolume = 6.3;
       bugatti.manufacturerCountry = "Italy";
       bugatti.ownerFirstName = "Amigo";
       bugatti.productionYear = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.seatsInTheCar = 2;
       bugatti.maxSpeed = 378;
       bugatti.model = "Bugatti Veyron";

   }

}
Chúng tôi đã tạo một đối tượng Xe hơi mới . Có một vấn đề: chúng tôi có 16 trường, nhưng chúng tôi chỉ khởi tạo 12 trường ! Bây giờ hãy xem mã và cố gắng tìm các trường chúng tôi đã quên! Không dễ dàng như vậy, huh? Trong tình huống này, một lập trình viên có thể dễ dàng mắc lỗi và không thể khởi tạo một số trường. Kết quả là, chương trình sẽ hoạt động không chính xác:
public class Car {

   String model;// model
   int maxSpeed;// maximum speed
   int wheels;// wheel width
   double engineVolume;// engine volume
   String color;// color
   int productionYear;// production year
   String ownerFirstName;// first name of owner
   String ownerLastName;// last name of owner
   long price;// price
   boolean isNew;// flag indicating whether car is new
   int seatsInTheCar;// number of seats in the car
   String cabinMaterial;// interior material
   boolean insurance;// flag indicating whether car is insured
   String manufacturerCountry;// manufacturer country
   int trunkVolume;// size of the trunk
   int accelerationTo100km;// how long it takes to accelerate to 100 km/h (in seconds)


   public static void main(String[] args) {
       Car bugatti = new Car();

       bugatti.color = "blue";
       bugatti.accelerationTo100km = 3;
       bugatti.engineVolume = 6.3;
       bugatti.manufacturerCountry = "Italy";
       bugatti.ownerFirstName = "Amigo";
       bugatti.productionYear = 2016;
       bugatti.insurance = true;
       bugatti.price = 2000000;
       bugatti.isNew = false;
       bugatti.seatsInTheCar = 2;
       bugatti.maxSpeed = 378;
       bugatti.model = "Bugatti Veyron";

       System.out.println("Model: Bugatti Veyron. Engine volume: " + bugatti.engineVolume + ". Trunk volume: " + bugatti.trunkVolume + ". Cabin material: " + bugatti.cabinMaterial +
       ". Wheel width: " + bugatti.wheels + ". Purchased in 2018 by Mr. " + bugatti.ownerLastName);

   }

}
Đầu ra bảng điều khiển: Model: Bugatti Veyron. Thể tích động cơ: 6.3. Thể tích thùng: 0. Vật liệu cabin: null. Chiều rộng bánh xe: 0. Được mua vào năm 2018 bởi Mr. null Người mua của bạn, người đã trả 2 triệu USD cho chiếc xe, rõ ràng sẽ không thích bị gọi là " Mr. null "! Nhưng nghiêm túc mà nói, điểm mấu chốt là chương trình của chúng ta đã tạo ra một đối tượng không chính xác: một chiếc ô tô có chiều rộng bánh xe bằng 0 (tức là không có bánh xe nào), một chiếc cốp bị mất, một cabin làm bằng vật liệu không xác định và trên hết là chủ sở hữu không xác định . Bạn chỉ có thể tưởng tượng một lỗi như vậy có thể "xảy ra" như thế nào khi chương trình đang chạy! Chúng ta cần tránh những tình huống như vậy bằng cách nào đó. Chúng tôi cần hạn chế chương trình của mình: khi tạo Xe mớiđối tượng, chúng tôi muốn các trường, chẳng hạn như kiểu máy và tốc độ tối đa, luôn được chỉ định. Mặt khác, chúng tôi muốn ngăn chặn việc tạo đối tượng. Các nhà xây dựng xử lý nhiệm vụ này một cách dễ dàng. Họ có tên của họ vì một lý do. Hàm tạo tạo ra một loại "khung" lớp mà mỗi đối tượng mới phải khớp với nhau. Để thuận tiện, chúng ta hãy quay lại phiên bản đơn giản hơn của lớp Car với hai trường. Xem xét các yêu cầu của chúng ta, phương thức khởi tạo của lớp Car sẽ như thế này:
public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}

// And creating an object now looks like this:

public static void main(String[] args) {
   Car bugatti = new Car("Bugatti Veyron", 378);
}
Lưu ý cách khai báo hàm tạo. Nó tương tự như một phương thức thông thường, nhưng nó không có kiểu trả về. Hơn nữa, hàm tạo chỉ định tên lớp ( Car ) bắt đầu bằng một chữ cái viết hoa. Ngoài ra, hàm tạo được sử dụng với một từ khóa mới đối với bạn: this . Từ khóa this dùng để chỉ một đối tượng cụ thể. Mã trong hàm tạo
public Car(String model, int maxSpeed) {
   this.model = model;
   this.maxSpeed = maxSpeed;
}
có thể được diễn giải gần như nguyên văn: " Mô hình của chiếc xe này (chiếc chúng tôi đang tạo) là đối số mô hình được truyền cho hàm tạo. Tốc độ tối đa cho chiếc xe này (chiếc chúng tôi đang tạo) là đối số maxSpeed ​​được truyền cho người xây dựng." Và đó chỉ là những gì xảy ra:
public class Car {

   String model;
   int maxSpeed;

   public Car(String model, int maxSpeed) {
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   public static void main(String[] args) {
       Car bugatti = new Car("Bugatti Veyron", 378);
       System.out.println(bugatti.model);
       System.out.println(bugatti.maxSpeed);
   }

}
Đầu ra bảng điều khiển: Bugatti Veyron 378 Trình xây dựng đã gán chính xác các giá trị được yêu cầu. Bạn có thể nhận thấy rằng hàm tạo rất giống với phương thức thông thường! Nên nó là. Hàm tạo thực sự là một phương thức, nhưng với các tính năng cụ thể :) Cũng giống như với các phương thức, chúng tôi đã truyền các đối số cho hàm tạo của mình. Và cũng giống như việc gọi một phương thức, việc gọi một hàm tạo sẽ không hoạt động trừ khi bạn chỉ định chúng:
public class Car {

   String model;
   int maxSpeed;

   public Car(String model, int maxSpeed) {
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   public static void main(String[] args) {
       Car bugatti = new Car(); // Error!
   }

}
Bạn có thể thấy rằng hàm tạo hoàn thành những gì chúng tôi đang cố gắng đạt được. Bây giờ bạn không thể tạo một chiếc ô tô mà không có tốc độ hoặc mô hình! Sự giống nhau giữa hàm tạo và phương thức không kết thúc ở đây. Cũng giống như các phương thức, hàm tạo có thể bị quá tải. Hãy tưởng tượng bạn có 2 con mèo cưng ở nhà. Bạn có một trong số họ như một con mèo con. Nhưng cái thứ hai bạn lấy từ đường phố khi nó đã lớn và bạn không biết chính xác nó bao nhiêu tuổi. Trong trường hợp này, chúng tôi muốn chương trình của mình có thể tạo hai loại mèo: loại có tên và tuổi (đối với con mèo đầu tiên) và loại chỉ có tên (đối với con mèo thứ hai). Đối với điều này, chúng tôi sẽ quá tải hàm tạo:
public class Cat {

   String name;
   int age;

   // For the first cat
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   // For the second cat
   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 5);
       Cat streetCatNamedBob = new Cat("Bob");
   }

}
Ngoài hàm tạo ban đầu có tham số "tên" và "tuổi", chúng tôi đã thêm một hàm tạo khác chỉ với tham số tên. Cũng giống như cách mà chúng ta đã quá tải các phương thức trong các bài học trước. Bây giờ chúng ta có thể tạo cả hai loại mèo :)
Tại sao chúng ta cần các nhà xây dựng?  - 2
Hãy nhớ rằng ở phần đầu của bài học, chúng tôi đã nói rằng bạn đã sử dụng hàm tạo mà không nhận ra? Chúng tôi có nghĩa là những gì chúng tôi nói. Thực tế là mọi lớp trong Java đều có cái được gọi là hàm tạo mặc định. Nó không nhận bất kỳ đối số nào, nhưng nó được gọi mỗi khi bạn tạo bất kỳ đối tượng nào của bất kỳ lớp nào.
public class Cat {

   public static void main(String[] args) {

       Cat smudge = new Cat(); // The default constructor is invoked here
   }
}
Thoạt nhìn, nó vô hình. Chúng tôi đã tạo một đối tượng, vậy thì sao? Nhà xây dựng đang làm gì ở đây? Để xem nó, chúng ta hãy viết rõ ràng một hàm tạo trống cho lớp Cat . Chúng tôi sẽ hiển thị một số cụm từ bên trong nó. Nếu cụm từ được hiển thị, thì hàm tạo đã được gọi.
public class Cat {

   public Cat() {
       System.out.println("A cat has been created!");
   }

   public static void main(String[] args) {

       Cat smudge = new Cat(); // The default constructor is invoked here
   }
}
Đầu ra bảng điều khiển: Một con mèo đã được tạo! Có xác nhận! Hàm tạo mặc định luôn hiện diện vô hình trong các lớp của bạn. Nhưng bạn cần biết một điều nữa về nó. Hàm tạo mặc định bị loại bỏ khỏi một lớp sau khi bạn tạo một hàm tạo có đối số. Trên thực tế, chúng ta đã thấy bằng chứng về điều này ở trên. Đó là trong mã này:
public class Cat {

   String name;
   int age;

   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   public static void main(String[] args) {

       Cat smudge = new Cat(); //Error!
   }
}
Chúng ta không thể tạo một Cat mà không có tên và tuổi, bởi vì chúng ta đã khai báo một hàm tạo Cat với các tham số chuỗiint . Điều này khiến hàm tạo mặc định biến mất ngay lập tức khỏi lớp. Vì vậy, hãy nhớ rằng nếu bạn cần một số hàm tạo trong lớp của mình, bao gồm hàm tạo không có đối số, thì bạn sẽ phải khai báo nó một cách riêng biệt. Ví dụ, giả sử chúng ta đang tạo một chương trình cho phòng khám thú y. Phòng khám của chúng tôi muốn làm những việc tốt và giúp đỡ những chú mèo con vô gia cư không rõ tên và tuổi. Sau đó, mã của chúng tôi sẽ trông như thế này:
public class Cat {

   String name;
   int age;

   // For cats with owners
   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   // For street cats
   public Cat() {
   }

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 5);
       Cat streetCat = new Cat();
   }
}
Bây giờ chúng ta đã viết một hàm tạo mặc định rõ ràng, chúng ta có thể tạo cả hai loại mèo :) Như với bất kỳ phương thức nào, thứ tự của các đối số được truyền cho một hàm tạo là rất quan trọng. Hãy hoán đổi các đối số têntuổi trong hàm tạo của chúng ta.
public class Cat {

   String name;
   int age;

   public Cat(int age, String name) {
       this.name = name;
       this.age = age;
   }

   public static void main(String[] args) {

       Cat smudge = new Cat("Smudge", 10); // Error!
   }
}
Một lỗi! Hàm tạo quy định rõ ràng rằng khi một đối tượng Cat được tạo, nó phải được truyền một số và một chuỗi theo thứ tự này. Vì vậy, mã của chúng tôi không hoạt động. Hãy chắc chắn ghi nhớ điều này và ghi nhớ nó khi khai báo các lớp của riêng bạn:
public Cat(String name, int age) {
   this.name = name;
   this.age = age;
}

public Cat(int age, String name) {
   this.age = age;
   this.name = name;
}
Đây là hai hàm tạo hoàn toàn khác nhau! Nếu chúng ta diễn đạt trong một câu câu trả lời cho câu hỏi "Tại sao tôi cần một hàm tạo?", chúng ta có thể nói, "Để đảm bảo rằng các đối tượng luôn có trạng thái hợp lệ". Khi bạn sử dụng hàm tạo, tất cả các biến của bạn sẽ được khởi tạo chính xác. Các chương trình của bạn sẽ không có bất kỳ ô tô nào có tốc độ bằng 0 hoặc bất kỳ đối tượng "không hợp lệ" nào khác. Lợi ích chính của họ là dành cho lập trình viên. Nếu bạn khởi tạo các trường theo cách thủ công (sau khi tạo một đối tượng), sẽ có rủi ro lớn là bạn sẽ bỏ sót điều gì đó và gây ra lỗi. Nhưng điều này sẽ không xảy ra với hàm tạo: nếu bạn không chuyển được tất cả các đối số được yêu cầu hoặc bạn chuyển sai loại đối số, trình biên dịch sẽ ngay lập tức báo lỗi. Chúng tôi cũng phải nói riêng rằng bạn không nên đặt chương trình của mình' s logic bên trong một hàm tạo. Đây là những phương pháp dành cho. Các phương thức là nơi bạn nên xác định tất cả các chức năng cần thiết. Hãy xem tại sao việc thêm logic vào hàm tạo là một ý tưởng tồi:
public class CarFactory {

   String name;
   int age;
   int carsCount;

   public CarFactory(String name, int age, int carsCount) {
   this.name = name;
   this.age = age;
   this.carsCount = carsCount;

   System.out.println("Our car factory is called " + this.name);
   System.out.println("It was founded " + this.age + " years ago" );
   System.out.println("Since that time, it has produced " + this.carsCount +  " cars");
   System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
}

   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Ford", 115 , 50000000);
   }
}
Chúng ta có một lớp CarFactory mô tả nhà máy ô tô. Bên trong hàm tạo, chúng tôi khởi tạo tất cả các trường và bao gồm một số logic: chúng tôi hiển thị một số thông tin về nhà máy. Có vẻ như không có gì xấu về điều này. Chương trình hoạt động tốt. Sản lượng bảng điều khiển: Nhà máy sản xuất ô tô của chúng tôi có tên là Ford Nó được thành lập cách đây 115 năm Kể từ thời điểm đó, nó đã sản xuất 50000000 ô tô. Trung bình, nó sản xuất 434782 ô tô mỗi năm Nhưng chúng tôi thực sự đã đặt một mỏ bị trì hoãn thời gian. Và loại mã này rất dễ dẫn đến lỗi. Giả sử rằng bây giờ chúng ta đang nói không phải về Ford, mà là về một nhà máy mới tên là "Amigo Motors", tồn tại chưa đầy một năm và đã sản xuất được 1000 chiếc ô tô:
public class CarFactory {

   String name;
   int age;
   int carsCount;

   public CarFactory(String name, int age, int carsCount) {
   this.name = name;
   this.age = age;
   this.carsCount = carsCount;

   System.out.println("Our car factor is called " + this.name);
   System.out.println("It was founded " + this.age + " years ago" );
   System.out.println("Since that time, it has produced " + this.carsCount +  " cars");
   System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
}


   public static void main(String[] args) {

       CarFactory ford = new CarFactory("Amigo Motors", 0 , 1000);
   }
}
Đầu ra bảng điều khiển: Nhà máy sản xuất ô tô của chúng tôi có tên là Amigo Motors Ngoại lệ trong luồng "chính" java.lang.ArithmeticException: / by 0 Nó được thành lập cách đây 0 năm Kể từ thời điểm đó, nó đã sản xuất 1000 chiếc ô tô tại CarFactory. (CarFactory.java:15) tại CarFactory.main(CarFactory.java:23) Quá trình kết thúc với mã thoát 1 Bùm! Chương trình kết thúc với một số loại lỗi khó hiểu. Bạn có thể thử đoán nguyên nhân? Vấn đề nằm ở logic mà chúng ta đưa vào hàm tạo. Cụ thể hơn, dòng này:
System.out.println("On average, it produces " + (this.carsCount/this.age) + " cars per year");
Ở đây bạn đang thực hiện phép tính và chia số lượng ô tô được sản xuất theo tuổi của nhà máy. Và vì nhà máy của chúng tôi mới (tức là 0 tuổi), chúng tôi chia cho 0, điều mà chúng tôi không thể làm trong toán học. Do đó, chương trình kết thúc với một lỗi.

Chúng ta nên làm gì?

Đặt tất cả logic trong một phương pháp riêng biệt. Hãy gọi nó là printFactoryInfo() . Bạn có thể truyền một đối tượng CarFactory cho nó làm đối số. Bạn có thể đặt tất cả logic ở đó và đồng thời xử lý các lỗi tiềm ẩn (như lỗi của chúng tôi liên quan đến 0 năm). Để mỗi người của riêng mình. Constructor là cần thiết để thiết lập trạng thái đối tượng hợp lệ. Chúng tôi có các phương pháp cho logic kinh doanh. Đừng trộn cái này với cái kia. Để củng cố những gì bạn đã học, chúng tôi khuyên bạn nên xem một video bài học từ Khóa học Java của chúng tôi
Bình luận
  • Phổ biến
  • Mới
Bạn phải đăng nhập để đăng nhận xet
Trang này chưa có bất kỳ bình luận nào