1. ภาพรวม
โดยรวมแล้ว รูปแบบการออกแบบ แบ่งออกเป็นสามประเภท:
(1) โหมดสร้างสรรค์ ทั้งหมดห้าประเภท: โหมดวิธีโรงงาน, โหมดโรงงานนามธรรม, โหมดซิงเกิลตัน, โหมดตัวสร้างและโหมดต้นแบบ
(2) โหมดโครงสร้าง ทั้งหมดเจ็ดประเภท: โหมดอะแดปเตอร์, โหมดมัณฑนากร, โหมดพร็อกซี, โหมดปรากฏ, โหมดบริดจ์โหมดการรวมและโหมดความเพลิดเพลิน
(3) โหมดพฤติกรรม , ทั้งหมดสิบเอ็ด: โหมดนโยบาย, โหมดวิธีแม่แบบ, โหมดผู้สังเกตการณ์, โหมดย่อยซ้ำโหมดโซ่ความรับผิดชอบโหมดคำสั่งโหมดบันทึก, โหมดสถานะ, โหมดผู้เยี่ยมชม, โหมดตัวกลางและโหมดล่าม
2. หกหลักการออกแบบรูปแบบ
1. เปิดหลักการปิด
หลักการของการเปิดและปิดคือการเปิดให้ส่วนขยายและใกล้เคียงกับการดัดแปลง เมื่อต้องมีการขยายโปรแกรมคุณไม่สามารถแก้ไขรหัสต้นฉบับเพื่อให้ได้เอฟเฟกต์ปลั๊กร้อน
2. หลักการทดแทน Liskov
คำอธิบายอย่างเป็นทางการของมันค่อนข้างเป็นนามธรรมและสามารถใช้กับ Baidu ได้ ในความเป็นจริงมันสามารถเข้าใจได้ดังนี้ (1) ความสามารถของคลาสย่อยจะต้องมากกว่าหรือเท่ากับคลาสแม่นั่นคือวิธีที่คลาสแม่สามารถใช้และคลาสย่อยสามารถใช้ (2) สิ่งเดียวกันนี้เป็นจริงสำหรับค่าส่งคืน สมมติว่าเมธอดคลาสแม่ส่งคืนรายการและคลาสย่อยส่งคืน ArrayList ซึ่งแน่นอนสามารถทำได้ หากเมธอดคลาสแม่ส่งคืน ArrayList และคลาสเด็กส่งคืนรายการมันก็ไม่สมเหตุสมผล ที่นี่ความสามารถของคลาสย่อยในการส่งคืนค่ามีขนาดเล็กกว่าคลาสแม่ (3) นอกจากนี้ยังมีกรณีที่มีการโยนข้อยกเว้น วิธีการย่อยใด ๆ สามารถประกาศคลาสย่อยที่โยนวิธีการคลาสแม่เพื่อประกาศข้อยกเว้น
ไม่สามารถประกาศได้ว่าข้อยกเว้นที่ชั้นพาเรนต์ไม่ได้ประกาศถูกโยนทิ้ง
3. หลักการผกผันการพึ่งพาอาศัยกัน
นี่คือพื้นฐานของหลักการของการเปิดและปิดและเนื้อหาเฉพาะ: การเขียนโปรแกรมเชิงอินเตอร์เฟสโดยอาศัยสิ่งที่เป็นนามธรรมมากกว่าคอนกรีต
4. หลักการแยกอินเทอร์เฟซ
หลักการนี้หมายถึง: การใช้อินเทอร์เฟซที่แยกได้หลายตัวดีกว่าการใช้อินเทอร์เฟซเดียว นอกจากนี้ยังหมายถึงการลดระดับการมีเพศสัมพันธ์ระหว่างชั้นเรียน จากที่นี่เราจะเห็นได้ว่ารูปแบบการออกแบบเป็นแนวคิดการออกแบบของซอฟต์แวร์โดยเริ่มจากสถาปัตยกรรมซอฟต์แวร์ขนาดใหญ่เพื่อความสะดวกในการอัพเกรดและบำรุงรักษา ดังนั้นบทความข้างต้นจึงปรากฏขึ้นหลายครั้ง: ลดการพึ่งพาและลดการมีเพศสัมพันธ์
5. หลักการ Demeter
ทำไมหลักการของความรู้น้อยที่สุด? นั่นคือเอนทิตีหนึ่งควรโต้ตอบกับเอนทิตีอื่น ๆ ให้น้อยที่สุดเท่าที่จะเป็นไปได้เพื่อให้โมดูลการทำงานของระบบค่อนข้างเป็นอิสระ
6. หลักการใช้ซ้ำแบบคอมโพสิต
หลักการคือการพยายามใช้วิธีการสังเคราะห์/การรวมตัวมากกว่าการสืบทอด
3. โหมดการสร้าง
โหมดการสร้างมีห้าประเภท: โหมดวิธีโรงงานโหมดโรงงานนามธรรมโหมดซิงเกิลโหมดผู้สร้างและโหมดต้นแบบ
3.1. แบบจำลองวิธีการโรงงาน
โหมดวิธีการโรงงานแบ่งออกเป็นสามประเภท: โหมดโรงงานธรรมดาโหมดวิธีการโรงงานหลายโหมดและโหมดวิธีโรงงานคงที่
3.1.1. แบบจำลองโรงงานทั่วไป
แบบจำลองโรงงานธรรมดาคือการสร้างคลาสโรงงานและสร้างอินสแตนซ์ของบางคลาสที่ใช้อินเทอร์เฟซเดียวกัน
แพ็คเกจ com.mode.create; อินเทอร์เฟซสาธารณะ myInterface {public void print ();} แพ็คเกจ com.mode.create; คลาสสาธารณะ MyClassone ใช้ myInterface {@Override โมฆะสาธารณะพิมพ์ () {system.out.println ("myclassone"); - แพ็คเกจ com.mode.create; คลาสสาธารณะ MyClasstwo ใช้ myInterface {@Override โมฆะสาธารณะพิมพ์ () {system.out.println ("MyClasStwo"); - แพ็คเกจ com.mode.create; คลาสสาธารณะ MyFactory {Public MyInterface ผลิต (ประเภทสตริง) {ถ้า ("หนึ่ง" .Equals (ประเภท)) {ส่งคืน myclassone ใหม่ (); } อื่นถ้า ("สอง" .Equals (ประเภท)) {ส่งคืน myclasstwo ใหม่ (); } else {system.out.println ("ไม่พบประเภท"); คืนค่า null; - แพ็คเกจ com.mode.create; Public Class FactoryTest {โมฆะสาธารณะคงที่หลัก (String [] args) {myFactory Factory = new MyFactory (); myInterface myi = factory.produce ("หนึ่ง"); myi.print (); -ฉันคิดว่าผลลัพธ์ของการทดสอบจากโรงงานควรชัดเจน
มาทำความเข้าใจกับประโยคนี้อีกครั้ง: แบบจำลองโรงงานธรรมดาคือการสร้างคลาสโรงงานและสร้างอินสแตนซ์ของบางคลาสที่ใช้อินเทอร์เฟซเดียวกัน
3.1.2. โหมดวิธีโรงงานหลายโหมด
โหมดวิธีการโรงงานหลายวิธีเป็นการปรับปรุงโหมดวิธีการโรงงานธรรมดา โหมดวิธีการโรงงานหลายวิธีคือการจัดหาวิธีการหลายวิธีจากโรงงานเพื่อสร้างวัตถุแยกต่างหาก
มาดูรหัสโดยตรง เราปรับเปลี่ยน MyFactory และ Factorytest ดังนี้:
แพ็คเกจ com.mode.create; คลาสสาธารณะ myFactory {public myInterface produceOne () {return ใหม่ myclassone (); } สาธารณะ myInterface producetwo () {return ใหม่ myclasstwo (); - แพ็คเกจ com.mode.create; Public Class FactoryTest {โมฆะสาธารณะคงที่หลัก (String [] args) {myFactory Factory = new MyFactory (); myInterface myi = factory.produceone (); myi.print (); -ผลการดำเนินงานก็ชัดเจนมาก
มาทำความเข้าใจกับประโยคนี้อีกครั้ง: โหมดวิธีการโรงงานหลายโหมดเป็นการปรับปรุงโหมดวิธีการโรงงานทั่วไป โหมดวิธีการโรงงานหลายวิธีคือการจัดหาวิธีการหลายวิธีจากโรงงานเพื่อสร้างวัตถุแยกต่างหาก
3.1.3. โหมดวิธีโรงงานคงที่
โหมดวิธีการแบบคงที่ของโรงงานตั้งค่าวิธีการในโหมดวิธีการหลายวิธีด้านบนเป็นแบบคงที่และไม่จำเป็นต้องสร้างอินสแตนซ์เพียงแค่เรียกมันโดยตรง
มาดูรหัสโดยตรง เราปรับเปลี่ยน MyFactory และ Factorytest ดังนี้:
แพ็คเกจ com.mode.create; คลาสสาธารณะ myFactory {สาธารณะ myInterface productOne () {return ใหม่ myclassone (); } สาธารณะ myInterface producetwo () {return ใหม่ myclasstwo (); - แพ็คเกจ com.mode.create; Public Class FactoryTest {Public Static Void Main (String [] args) {myInterface myi = myFactory.produceOne (); myi.print (); -ผลลัพธ์ของการดำเนินการยังคงชัดเจนมาก
ตรวจสอบอีกครั้ง: โหมดวิธีการแบบคงที่ของโรงงานตั้งค่าวิธีการในโหมดวิธีการหลายวิธีด้านบนเป็นแบบคงที่และไม่จำเป็นต้องสร้างอินสแตนซ์เพียงแค่เรียกมันโดยตรง
3.2. รูปแบบโรงงานนามธรรม
มีปัญหากับรูปแบบวิธีการโรงงานที่การสร้างคลาสขึ้นอยู่กับคลาสโรงงานนั่นคือถ้าคุณต้องการขยายโปรแกรมคุณต้องปรับเปลี่ยนคลาสโรงงานซึ่งละเมิดหลักการปิด
ในการแก้ปัญหานี้ลองมาดูรูปแบบของโรงงานนามธรรม: สร้างคลาสโรงงานหลายคลาสเพื่อให้เมื่อต้องการฟังก์ชั่นใหม่คุณสามารถเพิ่มคลาสโรงงานใหม่ได้โดยตรงโดยไม่ต้องแก้ไขรหัสก่อนหน้า
สิ่งนี้สอดคล้องกับหลักการปิด
มาดูรหัสด้านล่าง:
MyInterface, Myclassone, Myclasstwo ยังคงไม่เปลี่ยนแปลง
มีการเพิ่มอินเทอร์เฟซและคลาสต่อไปนี้:
แพ็คเกจ com.mode.create; ผู้ให้บริการส่วนต่อประสานสาธารณะ {Public MyInterface Produce (); } package com.mode.create; คลาสสาธารณะ MyFactoryone ใช้ผู้ให้บริการ {@Override สาธารณะ myInterface ผลิต () {return new myclassone (); }} แพ็คเกจ com.mode.create; คลาสสาธารณะ MyFactoryTwo ใช้ผู้ให้บริการ {@Override สาธารณะ myInterface ผลิต () {ส่งคืน myclasstwo ใหม่ (); -ปรับเปลี่ยนการทดสอบคลาสการทดสอบดังต่อไปนี้:
แพ็คเกจ com.mode.create; Public Class FactoryTest {โมฆะสาธารณะคงที่หลัก (String [] args) {ผู้ให้บริการผู้ให้บริการ = new MyFactoryOne (); myInterface myi = provider.produce (); myi.print (); -ผลการดำเนินงานยังคงชัดเจน
ตรวจสอบอีกครั้ง: รูปแบบของโรงงานนามธรรมคือการสร้างคลาสโรงงานหลายคลาสดังนั้นเมื่อต้องการฟังก์ชั่นใหม่คุณสามารถเพิ่มคลาสโรงงานใหม่ได้โดยตรงโดยไม่ต้องแก้ไขรหัสก่อนหน้า
3.3. โหมดซิงเกิลตัน
รูปแบบ Singleton ไม่จำเป็นต้องมีคำอธิบายมากเกินไป
เพียงแค่ดูรหัส:
การทดสอบแพ็คเกจ; คลาสสาธารณะ myObject {ส่วนตัว myObject myObject; ส่วนตัว myObject () {} สาธารณะ myObject getInstance () {ถ้า (myObject! = null) {} else {myObject = new myObject (); } return myObject; -อย่างไรก็ตามสิ่งนี้จะทำให้เกิดปัญหามัลติเธรด สำหรับคำอธิบายโดยละเอียดคุณสามารถดูบทที่ 6 ในหนังสือ "เทคโนโลยีหลักของการเขียนโปรแกรมมัลติเธรด Java"
3.4. โหมดผู้สร้าง
รูปแบบการสร้าง: คือการแยกการสร้างวัตถุที่ซับซ้อนออกจากการเป็นตัวแทนเพื่อให้กระบวนการก่อสร้างเดียวกันสามารถสร้างการเป็นตัวแทนที่แตกต่างกัน
มันดูเป็นนามธรรมอย่างแท้จริง แต่ในความเป็นจริงมันเป็นนามธรรมมาก! - - -
โหมดผู้สร้างมักจะมีอักขระต่อไปนี้:
(1) Builder: ให้อินเทอร์เฟซนามธรรมเพื่อสร้างมาตรฐานการสร้างส่วนประกอบต่าง ๆ ของวัตถุผลิตภัณฑ์ อินเทอร์เฟซนี้ระบุว่าส่วนใดของวัตถุที่ซับซ้อนถูกสร้างขึ้นและไม่เกี่ยวข้องกับการสร้างส่วนประกอบวัตถุเฉพาะ
(2) คอนกรีตบัลเดอร์: ใช้อินเทอร์เฟซของตัวสร้างและกำหนดการสร้างส่วนต่าง ๆ ของวัตถุที่ซับซ้อนสำหรับตรรกะทางธุรกิจที่แตกต่างกัน หลังจากกระบวนการก่อสร้างเสร็จสมบูรณ์ตัวอย่างของผลิตภัณฑ์จะมีให้
(3) ผู้อำนวยการ: เรียกผู้สร้างเฉพาะเพื่อสร้างส่วนต่าง ๆ ของวัตถุที่ซับซ้อน ผู้สอนไม่ได้เกี่ยวข้องกับข้อมูลผลิตภัณฑ์เฉพาะ แต่มีหน้าที่รับผิดชอบในการรับรองว่าทุกส่วนของวัตถุนั้นถูกสร้างขึ้นไม่เหมือนใครหรือในลำดับที่แน่นอน
(4) ผลิตภัณฑ์: วัตถุที่ซับซ้อนที่จะสร้าง
เป็นเรื่องปกติที่จะสร้างคนร้ายในการพัฒนาเกมและข้อกำหนดคือ: วายร้ายต้องรวมถึงศีรษะร่างกายและเท้า
มาดูรหัสต่อไปนี้:
ผลิตภัณฑ์ (วัตถุที่ซับซ้อนที่จะสร้าง):
แพ็คเกจ com.mode.create; บุคคลชั้นเรียนสาธารณะ {หัวหน้าสตริงส่วนตัว; ตัวสตริงส่วนตัว; เท้าสตริงส่วนตัว สตริงสาธารณะ gethead () {return head; } โมฆะสาธารณะ sethead (หัวสตริง) {this.head = head; } Public String getBody () {body return; } โมฆะสาธารณะ setbody (ตัวสตริง) {this.body = body; } สตริงสาธารณะ getFoot () {return foot; } โมฆะสาธารณะ setfoot (เท้าสตริง) {this.foot = foot; - Builder (ให้อินเทอร์เฟซนามธรรมเพื่อสร้างมาตรฐานการสร้างส่วนประกอบต่าง ๆ ของวัตถุผลิตภัณฑ์อินเทอร์เฟซนี้ระบุว่าส่วนใดของวัตถุที่ซับซ้อนถูกสร้างขึ้นเพื่อนำไปใช้และไม่เกี่ยวข้องกับการสร้างส่วนประกอบวัตถุเฉพาะ):
แพ็คเกจ com.mode.create; ส่วนต่อประสานสาธารณะ personbuilder {void buildhead (); เป็นโมฆะ buildbody (); เป็นโมฆะ buildfoot (); Person Buildperson ();} ConcreteBuilder (ใช้อินเทอร์เฟซตัวสร้างซึ่งรวบรวมการสร้างส่วนต่าง ๆ ของวัตถุที่ซับซ้อนสำหรับตรรกะทางธุรกิจที่แตกต่างกันหลังจากกระบวนการก่อสร้างเสร็จสมบูรณ์ให้ตัวอย่างของผลิตภัณฑ์):
แพ็คเกจ com.mode.create; ManBuilder ชั้นเรียนสาธารณะใช้ PersonBuilder {บุคคลบุคคล; manbuilder สาธารณะ () {person = บุคคลใหม่ (); } โมฆะสาธารณะ buildbody () {person.setbody ("สร้างร่างกายของมนุษย์"); } โมฆะสาธารณะ buildfoot () {person.setfoot ("สร้างเท้าของผู้ชาย"); } โมฆะสาธารณะ buildhead () {person.sethead ("สร้างหัวของผู้ชาย"); } Public Person BuildPerson () {บุคคลที่กลับมา; }} ผู้อำนวยการ (เรียกผู้สร้างเฉพาะเพื่อสร้างส่วนต่าง ๆ ของวัตถุที่ซับซ้อนผู้สอนไม่ได้เกี่ยวข้องกับข้อมูลผลิตภัณฑ์เฉพาะมันเป็นเพียงหน้าที่ในการรับรองว่าส่วนของวัตถุนั้นถูกสร้างขึ้นไม่สมบูรณ์หรือตามลำดับที่แน่นอน):
แพ็คเกจ com.mode.create; Persondirector ชั้นเรียนสาธารณะ {บุคคลสาธารณะ constructperson (personbuilder pb) {pb.buildhead (); pb.buildbody (); pb.buildfoot (); ส่งคืน pb.buildperson (); - คลาสทดสอบ:
แพ็คเกจ com.mode.create; การทดสอบระดับสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {persondirector pd = persondirector ใหม่ (); บุคคลบุคคล = pd.constructperson (manbuilder ใหม่ ()); System.out.println (person.getbody ()); System.out.println (person.getfoot ()); System.out.println (person.gethead ()); -ผลการทำงาน:
รีวิว: รูปแบบตัวสร้าง: คือการแยกการสร้างวัตถุที่ซับซ้อนออกจากการเป็นตัวแทนเพื่อให้กระบวนการก่อสร้างเดียวกันสามารถสร้างการเป็นตัวแทนที่แตกต่างกัน
3.5. โหมดต้นแบบ
แนวคิดของรูปแบบนี้คือการใช้วัตถุเป็นต้นแบบคัดลอกและโคลนและสร้างวัตถุใหม่ที่คล้ายกับวัตถุดั้งเดิม
เมื่อพูดถึงการคัดลอกวัตถุฉันจะพูดถึงเรื่องนี้ร่วมกับการคัดลอกตื้นและการคัดลอกวัตถุอย่างลึกซึ้ง ก่อนอื่นคุณต้องเข้าใจแนวคิดของการคัดลอกวัตถุลึกและตื้น ๆ :
สำเนาตื้น: หลังจากคัดลอกวัตถุตัวแปรของชนิดข้อมูลพื้นฐานจะถูกสร้างขึ้นใหม่ในขณะที่ประเภทการอ้างอิงชี้ไปยังวัตถุดั้งเดิม
สำเนาลึก: หลังจากคัดลอกวัตถุทั้งชนิดข้อมูลพื้นฐานและประเภทการอ้างอิงจะถูกสร้างขึ้นใหม่ พูดง่ายๆการคัดลอกลึกจะถูกคัดลอกอย่างสมบูรณ์ในขณะที่การคัดลอกตื้นไม่ได้ละเอียด
เขียนตัวอย่างการคัดลอกความลึก:
แพ็คเกจ com.mode.create; นำเข้า Java.io.ByTearrayInputStream; นำเข้า Java.io.ByTeArrayOutputStream; นำเข้า Java.io.ioException; นำเข้า Java.io.ObjectInputStream; นำเข้า Java.io.ObjectOutputStream; นำเข้า Java.io.Serializable; ต้นแบบระดับสาธารณะใช้ cloneable, serializable {ส่วนตัวคงที่สุดท้าย long serialversionuid = 1l; ฐาน int ส่วนตัว; จำนวนเต็มส่วนตัว OBJ; /* สำเนาตื้น*/ object clone () พ่น clonenotsupportedexception {// เนื่องจากอินเตอร์เฟส cloneable เป็นอินเทอร์เฟซที่ว่างเปล่าคุณสามารถกำหนดชื่อวิธีการของคลาสการใช้งานที่ Will // เช่น clonea หรือ cloneB Prototype proto = (ต้นแบบ) super.clone (); คืนโปรโต; } /* สำเนาลึก* / วัตถุสาธารณะ DeepClone () พ่น IOException, classnotFoundException { /* เขียนไบนารีสตรีมไปยังวัตถุปัจจุบัน* / byteArrayOutputStream bos = new ByteArrayOutputStream (); ObjectOutputStream OOS = ใหม่ ObjectOutputStream (BOS); oos.writeObject (นี่); /* อ่านวัตถุใหม่ที่สร้างขึ้นโดยสตรีมไบนารี*/ byteArrayInputStream bis = byTearrayInputStream ใหม่ (bos.tobyteArray ()); ObjectInputStream OIS = ใหม่ ObjectInputStream (bis); return ois.readObject (); } สาธารณะ int getBase () {ฐานกลับ; } โมฆะสาธารณะ setBase (ฐาน int) {this.base = base; } จำนวนเต็มสาธารณะ getObj () {return obj; } โมฆะสาธารณะ setObj (จำนวนเต็ม obj) {this.obj = obj; - คลาสทดสอบ:
แพ็คเกจ com.mode.create; นำเข้า java.io.ioException; การทดสอบระดับสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่น clonenotsupportedexception, classnotfoundexception, ioexception {prototype prototype = rototype ใหม่ (); Prototype.setBase (1); prototype.setobj (จำนวนเต็มใหม่ (2)); /* สำเนาตื้น*/ ต้นแบบต้นแบบ 1 = (ต้นแบบ) prototype.clone (); /* Deep Copy*/ Prototype Prototype2 = (Prototype) Prototype.deepClone (); System.out.println (Prototype1.getobj () == Prototype1.getobj ()); System.out.println (prototype1.getobj () == prototype2.getobj ()); -ผลการทำงาน:
ข้างต้นเป็นเรื่องเกี่ยวกับบทความนี้ฉันหวังว่ามันจะเป็นประโยชน์กับการเรียนรู้ของทุกคน