การเขียนโปรแกรมเชิงมุมมองกับการเขียนโปรแกรมเชิงวัตถุ


199

เช่นนักพัฒนาส่วนใหญ่ที่นี่และทั่วโลกฉันได้พัฒนาระบบซอฟต์แวร์โดยใช้เทคนิคการเขียนโปรแกรมเชิงวัตถุ (OOP) เป็นเวลาหลายปี ดังนั้นเมื่อฉันอ่านการเขียนโปรแกรมเชิงกว้าง (AOP) ที่อยู่ปัญหาหลายอย่างที่ OOP แบบดั้งเดิมไม่สามารถแก้ได้อย่างสมบูรณ์หรือโดยตรงฉันหยุดและคิดว่ามันจริงหรือไม่

ฉันได้อ่านข้อมูลมากมายที่พยายามเรียนรู้ถึงกุญแจของกระบวนทัศน์ AOP นี้และฉันอยู่ในที่เดียวกันดังนั้นฉันจึงต้องการเข้าใจถึงประโยชน์ของมันในการพัฒนาแอปพลิเคชันโลกแห่งความเป็นจริงมากขึ้น

มีใครมีคำตอบบ้างไหม?


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

คำตอบ:


323

ทำไม "vs" ไม่ใช่ "vs" คุณสามารถใช้การเขียนโปรแกรม Aspect Oriented เมื่อใช้ร่วมกับการเขียนโปรแกรมที่ใช้งานได้ แต่ยังใช้ร่วมกับ Object Oriented one ไม่ใช่ "vs" เป็น "การเขียนโปรแกรมเชิงมุมมองด้วยการเขียนโปรแกรมเชิงวัตถุ"

สำหรับฉัน AOP เป็น "meta-programming" บางประเภท ทุกสิ่งที่ AOP ทำได้ก็ทำได้โดยไม่ต้องเพิ่มรหัสอีก AOP เพียงช่วยให้คุณเขียนรหัสนี้

Wikipedia มีหนึ่งในตัวอย่างที่ดีที่สุดสำหรับการเขียนโปรแกรมเมตานี้ สมมติว่าคุณมีคลาสกราฟิกที่มีวิธี "set ... ()" มากมาย หลังจากแต่ละวิธีการตั้งค่าข้อมูลของกราฟิกที่มีการเปลี่ยนแปลงดังนั้นกราฟิกที่มีการเปลี่ยนแปลงและดังนั้นจึงต้องมีการปรับปรุงกราฟิกบนหน้าจอ สมมติว่าทาสีใหม่กราฟิกที่คุณต้องเรียกว่า "Display.update ()" วิธีคลาสสิกคือการแก้ปัญหานี้โดยการเพิ่มรหัสเพิ่มเติม ในตอนท้ายของแต่ละชุดวิธีการที่คุณเขียน

void set...(...) {
    :
    :
    Display.update();
}

หากคุณมีวิธีการตั้งค่า 3 วิธีนั่นไม่ใช่ปัญหา หากคุณมี 200 (สมมุติ) มันเจ็บปวดอย่างมากที่จะเพิ่มสิ่งนี้ทุกที่ นอกจากนี้เมื่อใดก็ตามที่คุณเพิ่มวิธีการตั้งค่าใหม่คุณต้องแน่ใจว่าจะไม่ลืมการเพิ่มสิ่งนี้ไปยังจุดสิ้นสุดมิฉะนั้นคุณเพิ่งสร้างข้อผิดพลาด

AOP แก้ปัญหานี้โดยไม่ต้องเพิ่มโค้ดแทน แต่คุณเพิ่มมุมมอง:

after() : set() {
   Display.update();
}

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

pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);

นั่นหมายความว่าอย่างไร? ซึ่งหมายความว่าถ้าวิธีการที่มีชื่อว่า "ชุด *" (* หมายถึงชื่อใด ๆ ที่อาจตามมาหลังจากชุด) โดยไม่คำนึงถึงสิ่งที่เป็นวิธีการส่งกลับ (ดอกจันแรก) หรือสิ่งที่พารามิเตอร์จะใช้เวลา (ดอกจันสาม) และมันเป็นวิธีการของ MyGraphicsClass และนี้ class เป็นส่วนหนึ่งของแพ็คเกจ "com.company. *" ดังนั้นนี่คือ pointcut ชุด () และรหัสแรกของเราบอกว่า " หลังจากใช้วิธีการใด ๆ ที่เป็นชุดจุดตัดแล้วให้เรียกใช้รหัสต่อไปนี้"

ดูว่า AOP แก้ปัญหาที่นี่ได้อย่างไร จริงๆแล้วทุกอย่างที่อธิบายที่นี่สามารถทำได้ในเวลารวบรวม ตัวประมวลผลล่วงหน้า AOP สามารถแก้ไขแหล่งที่มาของคุณ (เช่นการเพิ่ม Display.update () ไปยังจุดสิ้นสุดของทุกวิธี set-pointcut) ก่อนที่จะรวบรวมคลาสเอง

อย่างไรก็ตามตัวอย่างนี้ยังแสดงข้อเสียข้อใหญ่ของ AOP AOP กำลังทำสิ่งที่โปรแกรมเมอร์หลาย ๆ คนคิดว่าเป็น " Anti-Pattern " รูปแบบที่แน่นอนเรียกว่า " Action at a distance "

การดำเนินการในระยะไกลเป็นรูปแบบการต่อต้าน (ข้อผิดพลาดทั่วไปที่รู้จัก) ซึ่งพฤติกรรมในส่วนหนึ่งของโปรแกรมนั้นแตกต่างกันไปอย่างยากลำบากตามที่ยากหรือเป็นไปไม่ได้ในการระบุการดำเนินการในส่วนอื่นของโปรแกรม

สำหรับมือใหม่ในโครงการฉันอาจอ่านโค้ดของชุดวิธีการใด ๆ และพิจารณาว่ามันใช้งานไม่ได้เนื่องจากดูเหมือนว่าจะไม่อัปเดตจอแสดงผล ฉันไม่เห็นเพียงแค่ดูโค้ดของ set-method หลังจากที่ถูกประมวลผลแล้วโค้ดอื่น ๆ จะถูก "Magical" ถูกประมวลผลเพื่ออัพเดตการแสดงผล ฉันคิดว่านี่เป็นข้อเสียที่ร้ายแรง! โดยการเปลี่ยนแปลงวิธีการอาจมีข้อผิดพลาดแปลก ๆ ความเข้าใจเพิ่มเติมเกี่ยวกับการไหลของรหัสของรหัสที่สิ่งบางอย่างดูเหมือนจะทำงานได้อย่างถูกต้อง แต่ไม่ชัดเจน

ปรับปรุง

เพื่อชี้แจงว่า: บางคนอาจมีความรู้สึกที่ฉันพูดว่า AOP เป็นสิ่งที่ไม่ดีและไม่ควรใช้ นั่นไม่ใช่สิ่งที่ฉันพูด! AOP เป็นคุณสมบัติที่ยอดเยี่ยม ฉันแค่พูดว่า "ใช้อย่างระมัดระวัง" AOP จะทำให้เกิดปัญหาหากคุณรวมรหัสปกติและ AOP สำหรับAspectเดียวกันเท่านั้น ในตัวอย่างข้างต้นเรามีมุมมองในการปรับปรุงค่าของวัตถุกราฟิกและทาสีวัตถุที่ได้รับการปรับปรุง อันที่จริงแล้วเป็นแง่มุมเดียว การเข้ารหัสครึ่งหนึ่งของรหัสนี้เป็นรหัสปกติและอีกครึ่งหนึ่งเป็นรหัสคือสิ่งที่เพิ่มปัญหา

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

ดังนั้นการใช้งาน AOP ที่ดีในตัวอย่างของฉันคือการบันทึกทุกครั้งที่มีการอัพเดทค่าใด ๆ ผ่านวิธีการตั้งค่า สิ่งนี้จะไม่สร้างรูปแบบการต่อต้านและแทบจะไม่เคยเป็นสาเหตุของปัญหาใด ๆ

อาจกล่าวได้ว่าหากคุณสามารถใช้ AOP ในทางที่ผิดเพื่อสร้างปัญหามากมายมันเป็นความคิดที่ดีที่จะใช้มันทั้งหมด อย่างไรก็ตามเทคโนโลยีใดที่ไม่สามารถถูกทำร้ายได้? คุณสามารถใช้การห่อหุ้มข้อมูลในทางที่ผิดคุณสามารถละเมิดมรดก เทคโนโลยีการเขียนโปรแกรมที่เป็นประโยชน์ทุกอย่างสามารถถูกทารุณกรรมได้ พิจารณาภาษาการเขียนโปรแกรมเพื่อ จำกัด ให้มีเฉพาะคุณสมบัติที่ไม่สามารถใช้งานในทางที่ผิด; ภาษาที่สามารถใช้ฟีเจอร์ได้เฉพาะในตอนแรกที่ตั้งใจจะใช้เท่านั้น ภาษาดังกล่าวจะถูก จำกัด จนสามารถพิสูจน์ได้ถ้ามันสามารถใช้สำหรับการเขียนโปรแกรมในโลกแห่งความเป็นจริง


4
ดูเหมือนว่าการบันทึกจะเป็นตัวอย่างหนึ่งที่ AOP ไม่ได้ส่งผลให้เกิดการกระทำที่ระยะทาง ในเวลานี้วิกิพีเดียเป็นตัวอย่างของการใช้มุมมองสำหรับสิ่งต่าง ๆ เช่นการตรวจสอบความปลอดภัยซึ่งทำให้การไหลเวียนของโปรแกรมเป็นเรื่องที่เข้าใจได้ง่ายขึ้น
kizzx2

7
@ kizzx2: จุดที่ดีในการเข้าสู่ระบบในความเป็นจริง - มันเป็นตัวอย่างที่ดีที่สุดที่ฉันเคยเห็นความแข็งแกร่งของ AOP โดยไม่ทราบเกี่ยวกับ AOP ขอบคุณสำหรับการแบ่งปัน!
ความผิดพลาด

@Mecki ตัวอย่างของคุณเรียบง่ายเกินไปและไม่สะท้อนกรณีการใช้งานทั่วไป ในตัวอย่างของคุณDisplay.updateไม่มีข้อโต้แย้งใด ๆ ถ้าเราต้องการส่งผ่านข้อโต้แย้ง (เช่นโดยทั่วไปlogฟังก์ชันจะต้องใช้messageพารามิเตอร์) เราไม่จำเป็นต้องเพิ่มรหัสสำเร็จรูปจำนวนมากเพื่อใช้เป็นวิธี AOP ใช่หรือไม่
Pacerier

3
@Pacerier ตัวอย่างของฉันง่ายขึ้นเพราะ SO ไม่มีฟอรัมการสอน ฉันแค่ตอบคำถามของผู้ถามอาจมีรายละเอียดมากกว่าที่จำเป็น หากคุณต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับ AOP ลองอ่านเอกสารประกอบของโปรแกรมเมอร์และหากคุณมีคำถามโดยละเอียดทำไมไม่ถามที่นี่? ไม่ไม่ได้อยู่ในความคิดเห็นไปและสร้างคำถามใหม่เพราะนั่นคือสิ่งที่เป็นเรื่องเกี่ยวกับ ฉันแน่ใจว่าบางคนจะสามารถขจัดข้อสงสัยของคุณในการตอบกลับ
Mecki

2
@Pacerier ขออภัย แต่ฉันไม่เห็นจุดของคุณ ดูที่นี่: stackoverflow.com/a/8843713/15809รหัสนี้บันทึกทุกการเรียกไปยังวิธีสาธารณะทุกวิธีรวมถึงประเภทและค่าอาร์กิวเมนต์ของวิธีการทั้งหมด คุณเขียนสิ่งนี้เพียงครั้งเดียวและไม่มีการเพิ่มรหัส boilerplate ให้กับวิธีใด ๆ มันเป็นเพียงรหัสที่แสดงในคำตอบ
Mecki

29

pogramming ที่มุ่งเน้นด้านการจัดให้มีวิธีที่ดีในการใช้ความกังวลข้ามตัดเช่นการเข้าสู่ระบบความปลอดภัย สิ่งตัดขวางที่ตัดกันเหล่านี้เป็นชิ้นส่วนของตรรกะที่ต้องใช้ในหลาย ๆ ที่ แต่จริงๆแล้วไม่มีอะไรเกี่ยวข้องกับตรรกะทางธุรกิจ

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

  1. ตรรกะสำหรับข้อกังวลแต่ละข้อนั้นอยู่ในที่เดียวเมื่อเทียบกับการกระจัดกระจายไปทั่วฐานรหัส

  2. คลาสมีความสะอาดเนื่องจากมีเพียงรหัสสำหรับความกังวลหลัก (หรือฟังก์ชันการทำงานหลัก) และข้อกังวลที่สองถูกย้ายไปด้านต่างๆ


27

OOP และ AOP ไม่ได้เกิดร่วมกัน AOP สามารถเพิ่ม OOP ได้ดี AOP มีประโยชน์อย่างยิ่งสำหรับการเพิ่มรหัสมาตรฐานเช่นการบันทึกการติดตามประสิทธิภาพ ฯลฯ ไปยังวิธีการต่างๆโดยไม่อุดตันรหัสวิธีด้วยรหัสมาตรฐานนี้


10

ฉันคิดว่าไม่มีคำตอบทั่วไปสำหรับคำถามนี้ แต่สิ่งหนึ่งที่ควรสังเกตคือ AOP นั้นไม่ได้แทนที่ OOP แต่เพิ่มคุณสมบัติการสลายตัวบางอย่างซึ่งจัดการกับสิ่งที่เรียกว่าการปกครองแบบเผด็จการ ( 1 ) (หรือการตัดขวางที่เกี่ยวข้อง)

มันช่วยได้อย่างแน่นอนในบางกรณีตราบใดที่คุณสามารถควบคุมเครื่องมือและภาษาเพื่อใช้สำหรับโครงการเฉพาะ แต่ยังเพิ่มระดับความซับซ้อนใหม่เกี่ยวกับการโต้ตอบของแง่มุมและความต้องการเครื่องมือเพิ่มเติมเช่นAJDTเพื่อทำความเข้าใจ โปรแกรมของคุณ

เกรกอร์คิคซเล ส เคยให้พูดคุยที่น่าสนใจเบื้องต้นเกี่ยวกับ AOP ที่พูดถึงเทคโนโลยี Google ซึ่งผมแนะนำให้ดู: มุมมองการเขียนโปรแกรมเชิง: Radical การวิจัยใน Modularity


8

ประการแรก AOP ทั้งหมดจะไม่แทนที่ OOP AOP ขยาย OOP แนวคิดและการปฏิบัติของ OOP ยังคงมีความเกี่ยวข้อง การมีการออกแบบวัตถุที่ดีอาจจะช่วยให้ขยายได้ง่ายขึ้นด้วยแง่มุมต่างๆ

ฉันคิดว่าความคิดที่ AOP นำมานั้นสำคัญ เราจำเป็นต้องหาวิธีที่จะนำข้อกังวลข้ามไปใช้กับคลาสที่แตกต่างกันในโปรแกรมของคุณโดยไม่ต้องเปลี่ยนคลาสเอง แต่ฉันคิดว่าในที่สุด AOP ก็จะกลายเป็นส่วนหนึ่งของเครื่องมืออื่น ๆ ที่เราใช้ไม่ใช่เครื่องมือหรือเทคนิคแยกต่างหาก เราเห็นสิ่งนี้เกิดขึ้นแล้ว

ภาษาไดนามิกสองสามอย่างเช่น Ruby และ Python มีโครงสร้างภาษาเช่นมิกซ์อินที่แก้ปัญหาเดียวกัน มันดูเหมือน AOP มาก แต่รวมเข้ากับภาษาได้ดีกว่า

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

ฉันไม่คิดว่าคุณจะต้องเรียนรู้กระบวนทัศน์ใหม่ทั้งหมดเพื่อใช้ AOP ความคิดนั้นน่าสนใจ แต่กำลังถูกดูดซับโดยเครื่องมือและภาษาที่มีอยู่อย่างช้าๆ เพียงรับทราบข้อมูลและทดลองใช้เครื่องมือเหล่านี้


1

AOP เป็นกระบวนทัศน์การเขียนโปรแกรมใหม่ที่เกี่ยวข้องกับแนวคิดนี้ ด้านคือเอนทิตีซอฟต์แวร์ที่ใช้ส่วนที่ไม่สามารถใช้งานได้เฉพาะของแอปพลิเคชัน

ฉันคิดว่าบทความนี้เป็นจุดเริ่มต้นที่ดีสำหรับการเขียนโปรแกรม Aspect Oriented: http://www.jaftalks.com/wp/index.php/introduction-to-aspect-oriented-programming/


1

ฉันมาช้าเพื่อตอบคำถามนี้ แต่เป็นหนึ่งในหัวข้อที่ฉันโปรดปรานดังนั้นให้ฉันแบ่งปันมุมมองของฉัน

OOPส่วนใหญ่จะใช้เพื่อจัดระเบียบตรรกะทางธุรกิจของคุณในขณะที่AOP ช่วยในการจัดระเบียบสิ่งที่ไม่ทำงานของคุณเช่นการตรวจสอบการบันทึกการทำธุรกรรมการจัดการความปลอดภัย ฯลฯ

วิธีนี้คุณสามารถแยกตรรกะทางธุรกิจของคุณด้วยตรรกะที่ไม่ใช่ตัวละครที่ทำให้โค้ดสะอาด

ข้อได้เปรียบของนากคือคุณสามารถใช้คำแนะนำ (ตัวอย่างการตรวจสอบ) อย่างสม่ำเสมอโดยไม่ต้องใช้อินเทอร์เฟซใด ๆ ที่ให้ความยืดหยุ่นในการปรับเปลี่ยนโดยไม่ต้องสัมผัสตรรกะทางธุรกิจ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.