Chúng tôi đã xem xét việc sử dụng một đối tượng đơn lẻ, nhưng bạn có thể chưa nhận ra rằng chiến lược này là một mẫu thiết kế và là một trong những cách được sử dụng nhiều nhất.

Trên thực tế, có rất nhiều mẫu này và chúng có thể được phân loại theo mục đích cụ thể của chúng.

phân loại mẫu

kiểu mẫu Ứng dụng
sáng tạo Một loại giải quyết vấn đề tạo đối tượng
Cấu trúc Các mẫu cho phép chúng tôi xây dựng hệ thống phân cấp lớp chính xác và có thể mở rộng trong kiến ​​trúc của chúng tôi
hành vi Cụm mẫu này tạo điều kiện cho sự tương tác an toàn và thuận tiện giữa các đối tượng trong một chương trình.

Thông thường, một mẫu được đặc trưng bởi vấn đề mà nó giải quyết. Chúng ta hãy xem xét một số mẫu mà chúng ta gặp thường xuyên nhất khi làm việc với Java:

Mẫu Mục đích
Độc thân Chúng ta đã quen thuộc với mẫu này — chúng ta sử dụng nó để tạo và truy cập một lớp không thể có nhiều hơn một thể hiện.
Trình lặp Chúng tôi cũng quen thuộc với điều này. Chúng tôi biết rằng mẫu này cho phép chúng tôi lặp lại một đối tượng bộ sưu tập mà không tiết lộ biểu diễn bên trong của nó. Nó được sử dụng với các bộ sưu tập.
bộ chuyển đổi Mẫu này kết nối các đối tượng không tương thích để chúng có thể hoạt động cùng nhau. Tôi nghĩ tên của mẫu bộ điều hợp giúp bạn hình dung chính xác nó làm gì. Đây là một ví dụ đơn giản từ cuộc sống thực: bộ chuyển đổi USB cho ổ cắm trên tường.
phương pháp mẫu

Mẫu lập trình hành vi giải quyết vấn đề tích hợp và cho phép bạn thay đổi các bước thuật toán mà không thay đổi cấu trúc của thuật toán.

Hãy tưởng tượng rằng chúng ta có một thuật toán lắp ráp ô tô dưới dạng một chuỗi các bước lắp ráp:

Khung gầm -> Thân máy -> Động cơ -> Nội thất cabin

Nếu chúng tôi đặt một khung gia cố, một động cơ mạnh hơn hoặc nội thất có thêm ánh sáng, chúng tôi không phải thay đổi thuật toán và trình tự trừu tượng vẫn giữ nguyên.

Người trang trí Mẫu này tạo các hàm bao cho các đối tượng để cung cấp cho chúng chức năng hữu ích. Chúng tôi sẽ xem xét nó như là một phần của bài viết này.

Trong Java.io, các lớp sau triển khai các mẫu:

Mẫu Nó được sử dụng ở đâu trong java.io
bộ chuyển đổi
phương pháp mẫu
Người trang trí

hoa văn trang trí

Hãy tưởng tượng rằng chúng ta đang mô tả một mô hình cho một thiết kế nhà.

Nói chung, cách tiếp cận trông như thế này:

Ban đầu, chúng tôi có thể lựa chọn một số loại nhà. Cấu hình tối thiểu là một tầng có mái che. Sau đó, chúng tôi sử dụng tất cả các loại trang trí để thay đổi các thông số bổ sung, điều này đương nhiên ảnh hưởng đến giá của ngôi nhà.

Chúng tôi tạo một lớp House trừu tượng:


public abstract class House {
	String info;
 
	public String getInfo() {
    	return info;
	}
 
	public abstract int getPrice();
}
    

Ở đây chúng ta có 2 phương pháp:

  • getInfo() trả về thông tin về tên và đặc điểm của ngôi nhà của chúng ta;
  • getPrice() trả về giá của cấu hình ngôi nhà hiện tại.

Chúng tôi cũng có các triển khai Nhà tiêu chuẩn - gạch và gỗ:


public class BrickHouse extends House {
 
	public BrickHouse() {
    	info = "Brick House";
	}
 
	@Override
	public int getPrice() {
    	return 20_000;
	}
}
 
public class WoodenHouse extends House {
 
	public WoodenHouse() {
    	info = "Wooden House";
	}
 
	@Override
	public int getPrice() {
    	return 25_000;
	}
}
    

Cả hai lớp đều kế thừa lớp House và ghi đè phương thức giá của nó, đặt giá tùy chỉnh cho một ngôi nhà tiêu chuẩn. Chúng tôi đặt tên trong hàm tạo.

Tiếp theo, chúng ta cần viết các lớp trang trí. Các lớp này cũng sẽ kế thừa lớp House . Để làm điều này, chúng ta tạo một lớp trang trí trừu tượng.

Đó là nơi chúng ta sẽ đặt logic bổ sung để thay đổi một đối tượng. Ban đầu, sẽ không có logic bổ sung và lớp trừu tượng sẽ trống.


abstract class HouseDecorator extends House {
}
    

Tiếp theo, chúng tôi tạo triển khai trang trí. Chúng tôi sẽ tạo một số lớp cho phép chúng tôi thêm các tính năng bổ sung cho ngôi nhà:


public class SecondFloor extends HouseDecorator {
	House house;
 
	public SecondFloor(House house) {
    	this.house = house;
	}
 
	@Override
	public int getPrice() {
    	return house.getPrice() + 20_000;
	}
 
	@Override
	public String getInfo() {
    	return house.getInfo() + " + second floor";
	}
}
    
Một người trang trí thêm tầng hai cho ngôi nhà của chúng tôi

Trình xây dựng trang trí chấp nhận một ngôi nhà mà chúng tôi sẽ "trang trí", tức là thêm các sửa đổi. Và chúng tôi ghi đè các phương thức getPrice()getInfo() , trả về thông tin về ngôi nhà mới được cập nhật dựa trên ngôi nhà cũ.


public class Garage extends HouseDecorator {
 
	House house;
	public Garage(House house) {
    	this.house = house;
	}
 
	@Override
	public int getPrice() {
    	return house.getPrice() + 5_000;
	}
 
	@Override
	public String getInfo() {
    	return house.getInfo() + " + garage";
	}
}
    
Một nhà trang trí thêm một nhà để xe vào nhà của chúng tôi

Bây giờ chúng ta có thể cập nhật ngôi nhà của mình bằng các vật trang trí. Để làm điều này, chúng ta cần tạo một ngôi nhà:


House brickHouse = new BrickHouse();
    

Tiếp theo, chúng tôi thiết lậpcăn nhàbiến tương đương với một trang trí mới, đi vào nhà của chúng tôi:


brickHouse = new SecondFloor(brickHouse); 
    

Của chúng tôicăn nhàbiến bây giờ là một ngôi nhà có tầng hai.

Hãy xem xét các trường hợp sử dụng liên quan đến người trang trí:

mã ví dụ đầu ra

House brickHouse = new BrickHouse(); 

  System.out.println(brickHouse.getInfo());
  System.out.println(brickHouse.getPrice());
                    

nhà gạch

20000


House brickHouse = new BrickHouse(); 

  brickHouse = new SecondFloor(brickHouse); 

  System.out.println(brickHouse.getInfo());
  System.out.println(brickHouse.getPrice());
                    

Nhà gạch + tầng 2

40000


House brickHouse = new BrickHouse();
 

  brickHouse = new SecondFloor(brickHouse);
  brickHouse = new Garage(brickHouse);

  System.out.println(brickHouse.getInfo());
  System.out.println(brickHouse.getPrice());
                    

Nhà gạch + tầng 2 + gara

45000


House woodenHouse = new SecondFloor(new Garage(new WoodenHouse())); 

  System.out.println(woodenHouse.getInfo());
  System.out.println(woodenHouse.getPrice());
                    

Nhà gỗ + gara + tầng 2

50000


House woodenHouse = new WoodenHouse(); 

  House woodenHouseWithGarage = new Garage(woodenHouse);

  System.out.println(woodenHouse.getInfo());
  System.out.println(woodenHouse.getPrice());

  System.out.println(woodenHouseWithGarage.getInfo());
  System.out.println(woodenHouseWithGarage.getPrice());
                    

Nhà gỗ

25000

Nhà gỗ + nhà để xe

30000

Ví dụ này minh họa lợi ích của việc nâng cấp đối tượng bằng trình trang trí. Vì vậy, chúng tôi đã không thay đổiNhà gỗchính đối tượng đó, mà thay vào đó tạo một đối tượng mới dựa trên đối tượng cũ. Ở đây chúng ta có thể thấy rằng ưu điểm đi kèm với nhược điểm: mỗi lần chúng ta tạo một đối tượng mới trong bộ nhớ, làm tăng mức tiêu thụ bộ nhớ.

Nhìn vào sơ đồ UML này của chương trình của chúng tôi:

Một trình trang trí có cách triển khai cực kỳ đơn giản và thay đổi động các đối tượng, nâng cấp chúng. Các trình tạo trang trí có thể được nhận dạng bởi các hàm tạo của chúng, chúng nhận các đối tượng tham số có cùng kiểu hoặc giao diện trừu tượng như lớp hiện tại. Trong Java, mẫu này được sử dụng rộng rãi trong các lớp I/O.

Ví dụ, như chúng ta đã lưu ý, tất cả các lớp con của java.io.InputStream , OutputStream , ReaderWriter đều có một hàm tạo chấp nhận các đối tượng của cùng một lớp.