"Chào, Amigo!"

"Chào, Bilaabo!"

"Chủ đề của chúng ta ngày hôm nay sẽ không chỉ thú vị - nó sẽ hết sức hoành tráng."

"Hôm nay tôi sẽ cho bạn biết các mẫu thiết kế là gì. "

"Tuyệt! Tôi đã nghe rất nhiều về họ. Tôi không thể chờ đợi!"

"Các lập trình viên có kinh nghiệm phải viết rất nhiều lớp. Nhưng phần khó khăn nhất của công việc này là quyết định lớp nào sẽ tạo và cách phân chia công việc giữa chúng."

"Càng giải quyết những câu hỏi như vậy, họ càng nhận ra rằng một số giải pháp là tốt, trong khi những giải pháp khác là xấu."

"Các giải pháp tồi thường tạo ra nhiều vấn đề hơn là chúng giải quyết được. Chúng mở rộng kém, tạo ra nhiều hạn chế không cần thiết, v.v. Còn các giải pháp tốt thì ngược lại."

"Có một số tương tự bạn có thể thực hiện?"

"Giả sử bạn đang xây một ngôi nhà. Và bạn đang nghĩ xem nó sẽ được làm bằng gì. Bạn quyết định rằng mình cần những bức tường, sàn nhà và trần nhà. Kết quả là bạn xây một ngôi nhà có mái bằng và không có mái bằng". nền móng. Một ngôi nhà như vậy sẽ bị nứt, và mái nhà sẽ bị dột. Đây là một giải pháp tồi."

"Ngược lại, một ngôi nhà bao gồm móng, tường và mái đầu hồi sẽ là một giải pháp tốt. Tuyết rơi dày không có vấn đề gì, vì tuyết sẽ trượt khỏi mái nhà. Và đất chuyển dịch không có gì đáng sợ, vì nền móng sẽ đảm bảo ổn định. Chúng tôi sẽ gọi một giải pháp như vậy là tốt."

"Tôi hiểu rồi. Cảm ơn."

"OK. Vậy tôi sẽ tiếp tục."

"Theo thời gian, các giải pháp tốt được gọi là các mẫu thiết kế, trong khi các giải pháp xấu được gọi là phản mẫu."

"Một mẫu thiết kế giống như một câu trả lời cho một câu hỏi. Sẽ khó hiểu nếu bạn chưa bao giờ nghe câu hỏi."

" Loại mẫu đầu tiên là mẫu sáng tạo. Các mẫu như vậy mô tả các giải pháp tốt liên quan đến việc tạo đối tượng."

"Việc tạo ra các đối tượng có gì phức tạp?"

"Khi nó xảy ra, đó chỉ là những gì chúng ta sẽ khám phá bây giờ."

Mẫu đơn.

Các mẫu thiết kế: singleton, factory, factory method, abstract factory - 1

"Thông thường trong các chương trình, chỉ có thể tồn tại một bản sao duy nhất của một số đối tượng. Ví dụ: bảng điều khiển, trình ghi nhật ký, trình thu gom rác, v.v."

" Giải pháp tồi: không tạo bất kỳ đối tượng nào — chỉ tạo một lớp có các phương thức tĩnh."

" Giải pháp tốt:  tạo một đối tượng duy nhất và lưu trữ nó trong một biến tĩnh. Ngăn việc tạo đối tượng thứ hai của lớp. Ví dụ:"

Ví dụ
class Sun
{
 private static Sun instance;
 public static Sun getInstance()
 {
  if (instance == null)
  instance = new Sun();

  return instance;
 }

 private Sun()
 {
 }
}
Nó được gọi như thế nào
Sun sun = Sun.getInstance();

"Thật đơn giản."

"Đầu tiên, chúng tôi đặt hàm tạo ở chế độ riêng tư. Bây giờ, nó chỉ có thể được gọi từ bên trong lớp của chúng tôi. Chúng tôi đã chặn việc tạo các đối tượng Mặt trời ở mọi nơi ngoại trừ bên trong các phương thức của lớp Mặt trời."

"Thứ hai, chỉ có thể lấy được một đối tượng của lớp này bằng cách gọi phương thức getInstance(). Đây không chỉ là phương thức duy nhất có thể tạo đối tượng Mặt trời, mà còn đảm bảo rằng chỉ có một đối tượng như vậy."

"Tôi hiểu rồi."

"Khi bạn nghĩ, «Bây giờ, chính xác thì tôi sẽ làm điều đó như thế nào?», một mẫu cho biết, «bạn có thể thử điều này — đây là một trong những giải pháp tốt nhất.»"

"Cảm ơn. Bây giờ mọi thứ đang bắt đầu trở nên rõ ràng."

"Bạn cũng có thể đọc về mô hình này  ở đây ."

Mô hình nhà máy.

Các mẫu thiết kế: singleton, factory, factory method, abstract factory - 2

"Đây là một tình huống mà các lập trình viên thường gặp phải. Bạn có một số lớp cơ sở và nhiều lớp con. Ví dụ: một lớp nhân vật trò chơi (GamePerson) và các lớp cho tất cả các nhân vật khác kế thừa nó."

"Giả sử bạn có các lớp sau:"

Ví dụ
abstract class GamePerson
{
}

class Warrior extends GamePerson
{
}

class Mag extends GamePerson
{
}

class Troll extends GamePerson
{
}

class Elf extends GamePerson
{
}

"Câu hỏi đặt ra là làm thế nào để chúng ta quản lý một cách linh hoạt và thuận tiện việc tạo ra các đối tượng của các lớp này."

"Nếu vấn đề này có vẻ xa vời đối với bạn, hãy tưởng tượng rằng trong trò chơi, bạn cần tạo ra hàng chục thanh kiếm và khiên, hàng trăm phép thuật và hàng nghìn quái vật. Bạn không thể làm gì nếu không có cách tiếp cận thuận tiện để tạo đối tượng ở đây. "

" Mẫu Factory cung cấp một giải pháp tốt."

"Đầu tiên, chúng ta cần tạo một enum có giá trị tương ứng với các lớp khác nhau."

"Thứ hai, tạo một lớp Factory đặc biệt có (các) phương thức tĩnh tạo (các) đối tượng dựa trên giá trị enum."

"Ví dụ:"

Ví dụ
public enum PersonType
{
 UNKNOWN,
 WARRIOR,
 MAG,
 TROLL,
 ELF,
}

public class PersonFactory
{
 public static GamePerson createPerson(PersonType personType)
 {
  switch(personType)
  {
   WARRIOR:
   return new Warrior();
   MAG:
   return new Mag();
   TROLL:
   return new Troll();
   ELF:
   return new Elf();
   default:
   throw new GameException();
  }
 }
}
Nó được gọi như thế nào
GamePerson person = PersonFactory.createPerson(PersonType.MAG);

"Nói cách khác, chúng tôi đã tạo một lớp đặc biệt để quản lý việc tạo đối tượng?"

"Chuẩn rồi."

"Vậy điều này mang lại lợi ích gì?"

"Đầu tiên, trong lớp này, các đối tượng có thể được khởi tạo với dữ liệu cần thiết."

"Thứ hai, bạn có thể chuyển giá trị enum cần thiết giữa các phương thức bao nhiêu tùy thích để cuối cùng tạo ra đối tượng mong muốn."

"Thứ ba, số lượng trường enum không nhất thiết phải khớp với số lượng lớp. Có thể có nhiều loại ký tự, nhưng ít lớp."

"Ví dụ: một Pháp sư & Chiến binh có thể sử dụng một lớp (Con người), nhưng với các thuộc tính sức mạnh và phép thuật khác nhau (đối số hàm tạo)."

"Đây là giao diện của nó (để rõ ràng, tôi cũng đã thêm yêu tinh bóng tối):"

Ví dụ
public enum PersonType
{
 UNKNOWN,
 WARRIOR,
 MAG,
 TROLL,
 ELF,
 DARK_ELF
}

public class PersonFactory
{
 public static GamePerson createPerson(PersonType personType)
 {
  switch(personType)
  {
   WARRIOR:
   return new Human(10, 0); // Strength, magic
   MAG:
   return new Human(0, 10); // Strength, magic
   TROLL:
   OGR:
   return new Troll();
   ELF:
   return new Elf(true); // true – good, false – evil
   DARK_ELF:
   return new Elf(false); // true – good, false – evil
   default:
   throw new GameException();
  }
 }
}
Nó được gọi như thế nào
GamePerson person = PersonFactory.createPerson(PersonType.MAG);

"Trong ví dụ trên, chúng tôi chỉ sử dụng ba lớp để tạo sáu loại đối tượng khác nhau. Điều này rất thuận tiện. Hơn nữa, chúng tôi tập trung tất cả logic này vào một lớp và một phương thức."

"Bây giờ, giả sử chúng ta quyết định tạo một lớp riêng cho Ogre — chúng ta chỉ cần thay đổi một vài dòng mã ở đây chứ không thay đổi một nửa ứng dụng."

"Tôi đồng ý. Đó là một giải pháp tốt."

"Và đó là những gì tôi đang nói đến: các mẫu thiết kế là tập hợp các giải pháp tốt."

“Tôi cũng ước mình biết sử dụng chúng ở đâu…”

"Vâng. Tôi đồng ý, bạn sẽ không hiểu ngay. Tuy nhiên, biết mà không làm được vẫn tốt hơn là không biết mà không làm được. Đây là một liên kết hữu ích khác dành cho bạn về mẫu này: Mẫu nhà máy "

"Ồ cảm ơn."

" Mô hình nhà máy trừu tượng ."

"Đôi khi khi bạn có nhiều đối tượng, ý tưởng tạo ra một nhà máy cho các nhà máy tự nảy ra. Nhà máy như vậy được gọi là nhà máy trừu tượng ."

"Cái này cần thiết ở đâu?!"

"Giả sử bạn có một số nhóm đối tượng giống hệt nhau. Điều này sẽ dễ hiển thị hơn bằng một ví dụ."

"Bây giờ, giả sử bạn có ba chủng tộc trong trò chơi của mình: con người, yêu tinh và ác quỷ. Và để cân bằng, mỗi chủng tộc đều có chiến binh, cung thủ và pháp sư. Người chơi chỉ có thể tạo ra các đồ vật thuộc về chủng tộc mà họ đang chơi cho trong trò chơi. Đây là giao diện của nó trong mã:"

Tuyên bố các lớp chiến sĩ
class Warrior
{
}
class Archer
{
}
class Mag
{
}
con người
class HumanWarrior extends Warrior
{
}

class HumanArcher extends Archer
{
}

class HumanMag extends Mag
{
}
yêu tinh
class ElfWarrior extends Warrior
{
}

class ElfArcher extends Archer
{
}

class ElfMag extends Mag
{
}
ác quỷ
class DaemonWarrior extends Warrior
{
}

class DaemonArcher extends Archer
{
}

class DaemonMag extends Mag
{
}

Và bây giờ hãy tạo ra các chủng tộc, hoặc chúng ta cũng có thể gọi chúng là quân đội.

quân đội
abstract class Army
{
 public Warrior createWarrior();
 public Archer createArcher();
 public Mag createMag();
}
quân nhân
class HumanArmy extends Army
{
 public Warrior createWarrior()
 {
  return new HumanWarrior();
 }
 public Archer createArcher()
 {
  return new HumanArcher();
 }
 public Mag createMag()
 {
  return new HumanMag();
 }
}
đội quân yêu tinh
class ElfArmy extends Army
{
 public Warrior createWarrior()
 {
  return new ElfWarrior();
 }
 public Archer createArcher()
 {
  return new ElfArcher();
 }
 public Mag createMag()
 {
  return new ElfMag();
 }
}
đội quân quỷ
class DaemonArmy extends Army
{
 public Warrior createWarrior()
 {
  return new DaemonWarrior();
 }
 public Archer createArcher()
 {
  return new DaemonArcher();
 }
 public Mag createMag()
 {
  return new DaemonMag();
 }
}

"Nhưng làm thế nào để bạn sử dụng điều này?"

"Bạn có thể sử dụng các lớp Quân đội, Chiến binh, Cung thủ và Pháp sư ở bất kỳ đâu trong chương trình và để tạo các đối tượng cần thiết — chỉ cần chuyển một đối tượng của lớp con Quân đội mong muốn."

"Ví dụ:"

Ví dụ
Army humans = new HumanArmy();
Army daemons = new DaemonArmy();

Army winner = FightSimulator.simulate(humans, daemons);

"Trong ví dụ trên, chúng ta có một lớp mô phỏng các trận chiến giữa các chủng tộc (quân đội) khác nhau. Bạn chỉ cần chuyển hai đối tượng Quân đội. Bản thân lớp sử dụng chúng để tạo ra các đội quân khác nhau và tiến hành các trận chiến ảo giữa chúng để xác định kẻ chiến thắng ."

"Tôi hiểu rồi. Cảm ơn. Một cách tiếp cận thực sự thú vị."

"Một giải pháp tốt, bất kể bạn nói gì."

"Chuẩn rồi."

"Đây là một liên kết tốt khác về chủ đề này:  Mô hình nhà máy trừu tượng "