เราได้ตรวจสอบการใช้งานของ singleton object แล้ว แต่คุณอาจยังไม่ทราบว่ากลยุทธ์นี้เป็นรูปแบบการออกแบบและเป็นหนึ่งในรูปแบบที่ใช้มากที่สุด

อันที่จริงมีรูปแบบเหล่านี้มากมายและสามารถจำแนกตามวัตถุประสงค์เฉพาะได้

การจำแนกรูปแบบ

ประเภทรูปแบบ แอปพลิเคชัน
สร้างสรรค์ ประเภทที่แก้ปัญหาการสร้างวัตถุ
โครงสร้าง รูปแบบที่ช่วยให้เราสร้างลำดับชั้นที่ถูกต้องและขยายได้ในสถาปัตยกรรมของเรา
พฤติกรรม กลุ่มของรูปแบบนี้อำนวยความสะดวกในการโต้ตอบอย่างปลอดภัยและสะดวกระหว่างวัตถุในโปรแกรม

โดยทั่วไปแล้ว รูปแบบจะมีลักษณะตามปัญหาที่แก้ได้ มาดูรูปแบบบางส่วนที่เราพบบ่อยที่สุดเมื่อทำงานกับ Java:

ลวดลาย วัตถุประสงค์
ซิงเกิ้ลตัน เราคุ้นเคยกับรูปแบบนี้อยู่แล้ว — เราใช้เพื่อสร้างและเข้าถึงคลาสที่ไม่สามารถมีมากกว่าหนึ่งอินสแตนซ์
วนซ้ำ เรายังคุ้นเคยกับสิ่งนี้ เราทราบดีว่ารูปแบบนี้ช่วยให้เราวนซ้ำวัตถุคอลเลกชันโดยไม่ต้องเปิดเผยการเป็นตัวแทนภายใน ใช้กับของสะสม
อแดปเตอร์ รูปแบบนี้เชื่อมต่อวัตถุที่เข้ากันไม่ได้เพื่อให้สามารถทำงานร่วมกันได้ ฉันคิดว่าชื่อของรูปแบบอะแดปเตอร์ช่วยให้คุณนึกภาพออกว่ามันใช้ทำอะไร นี่คือตัวอย่างง่ายๆ จากชีวิตจริง: อะแดปเตอร์ USB สำหรับเต้ารับติดผนัง
วิธีแม่แบบ

รูปแบบการเขียนโปรแกรมเชิงพฤติกรรมที่ช่วยแก้ปัญหาการรวมและช่วยให้คุณเปลี่ยนขั้นตอนของอัลกอริทึมโดยไม่ต้องเปลี่ยนโครงสร้างของอัลกอริทึม

ลองนึกภาพว่าเรามีอัลกอริทึมการประกอบรถยนต์ในรูปแบบของลำดับขั้นตอนการประกอบ:

แชสซี -> ตัวถัง -> เครื่องยนต์ -> ภายในห้องโดยสาร

หากเราใส่เฟรมเสริม เครื่องยนต์ที่ทรงพลังขึ้น หรือภายในห้องโดยสารที่มีไฟส่องสว่างเพิ่มเติม เราก็ไม่ต้องเปลี่ยนอัลกอริทึม และลำดับนามธรรมก็ยังคงเหมือนเดิม

มัณฑนากร รูปแบบนี้สร้าง wrapper สำหรับออบเจกต์เพื่อให้มีฟังก์ชันที่เป็นประโยชน์ เราจะถือว่าเป็นส่วนหนึ่งของบทความนี้

ใน Java.io คลาสต่อไปนี้ใช้รูปแบบ:

ลวดลาย ใช้ใน java.io ที่ไหน
อแดปเตอร์
วิธีแม่แบบ
มัณฑนากร

รูปแบบการตกแต่ง

ลองจินตนาการว่าเรากำลังอธิบายแบบจำลองสำหรับการออกแบบบ้าน

โดยทั่วไป วิธีการมีลักษณะดังนี้:

ในเบื้องต้นเรามีแบบบ้านให้เลือกหลายแบบ การกำหนดค่าขั้นต่ำคือหนึ่งชั้นพร้อมหลังคา จากนั้นเราใช้มัณฑนากรทุกประเภทเพื่อเปลี่ยนพารามิเตอร์เพิ่มเติมซึ่งส่งผลต่อราคาของบ้านโดยธรรมชาติ

เราสร้างคลาส House แบบนามธรรม:

public abstract class House {
	String info;

	public String getInfo() {
    	return info;
	}

	public abstract int getPrice();
}

ที่นี่เรามี 2 วิธี:

  • getInfo()ส่งคืนข้อมูลเกี่ยวกับชื่อและคุณสมบัติของบ้านของเรา
  • getPrice()ส่งกลับราคาของการกำหนดค่าบ้านปัจจุบัน

เรายังมีการติดตั้งแบบบ้านมาตรฐาน — อิฐและไม้:

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;
	}
}

ทั้งสองคลาสสืบทอด คลาส Houseและแทนที่เมธอดราคา โดยกำหนดราคาเองสำหรับบ้านมาตรฐาน เราตั้งชื่อในตัวสร้าง

ต่อไปเราต้องเขียนคลาสมัณฑนากร คลาสเหล่านี้จะสืบทอดคลาสHouse ด้วย ในการทำเช่นนี้ เราสร้างคลาสมัณฑนากรนามธรรม

นั่นคือจุดที่เราจะใส่ตรรกะเพิ่มเติมสำหรับการเปลี่ยนแปลงวัตถุ ในขั้นต้นจะไม่มีตรรกะเพิ่มเติมและคลาสนามธรรมจะว่างเปล่า

abstract class HouseDecorator extends House {
}

ต่อไป เราสร้างการใช้งานมัณฑนากร เราจะสร้างหลายชั้นเรียนที่ให้เราเพิ่มคุณสมบัติเพิ่มเติมให้กับบ้าน:

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";
	}
}
ช่างต่อเติมบ้านชั้นสองของเรา

คอนสตรัคเตอร์มัณฑนากรยอมรับบ้านที่เราจะ "ตกแต่ง" คือเพิ่มการดัดแปลง และเราลบล้างเมธอดgetPrice()และgetInfo()โดยส่งคืนข้อมูลเกี่ยวกับบ้านที่อัปเดตใหม่ตามบ้านเก่า

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";
	}
}
ช่างต่อเติมโรงจอดรถบ้านเรา

ตอนนี้เราสามารถปรับปรุงบ้านของเราด้วยมัณฑนากร ในการทำเช่นนี้เราต้องสร้างบ้าน:

House brickHouse = new BrickHouse();

ต่อไปเราตั้งค่าของเราบ้านตัวแปรเท่ากับมัณฑนากรคนใหม่ที่ผ่านในบ้านของเรา:

brickHouse = new SecondFloor(brickHouse);

ของเราบ้านตัวแปรคือบ้านที่มีชั้นสอง

ลองดูกรณีการใช้งานที่เกี่ยวข้องกับนักตกแต่ง:

ตัวอย่างโค้ด เอาต์พุต
House brickHouse = new BrickHouse();

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

บ้านอิฐ

20,000

House brickHouse = new BrickHouse();

  brickHouse = new SecondFloor(brickHouse);

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

บ้านอิฐ+ชั้นสอง

40000

House brickHouse = new BrickHouse();


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

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

บ้านอิฐ+ชั้น2+โรงรถ

45000

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

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

บ้านไม้+โรงจอดรถ+ชั้น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());

บ้านไม้

25000

บ้านไม้+โรงรถ

30000

ตัวอย่างนี้แสดงให้เห็นถึงประโยชน์ของการอัพเกรดวัตถุด้วยมัณฑนากร เราก็เลยไม่เปลี่ยนบ้านไม้วัตถุเอง แต่สร้างวัตถุใหม่ตามวัตถุเก่าแทน เราจะเห็นว่าข้อดีมาพร้อมกับข้อเสีย: เราสร้างวัตถุใหม่ในหน่วยความจำแต่ละครั้ง เพิ่มการใช้หน่วยความจำ

ดูแผนภาพ UML ของโปรแกรมของเรา:

มัณฑนากรมีการใช้งานที่เรียบง่ายสุด ๆ และเปลี่ยนแปลงอ็อบเจกต์แบบไดนามิก อัปเกรดพวกมัน มัณฑนากรสามารถรับรู้ได้โดยตัวสร้างของพวกเขาซึ่งใช้เป็นวัตถุพารามิเตอร์ของประเภทนามธรรมหรือส่วนต่อประสานเดียวกันกับคลาสปัจจุบัน ใน Java รูปแบบนี้ใช้กันอย่างแพร่หลายในคลาส I/O

ตัวอย่างเช่น ดังที่เราได้กล่าวไปแล้ว คลาสย่อยทั้งหมดของjava.io.InputStream , OutputStream , ReaderและWriterมีตัวสร้างที่ยอมรับออบเจกต์ของคลาสเดียวกัน