ระเบียบยักษ์ของ if
คำพูดคอยจ้องหน้าคุณอยู่เสมอ คุณรู้สึกว่าคุณ ควร สามารถลดความซับซ้อนได้ ยกเว้น Business Logic ที่คอยขัดขวาง
ตัวอย่างเช่น สมมติว่าคุณมีแพลตฟอร์มการขายที่คุณสร้าง Quote
s ซึ่งมี LineItem
. มากมาย ส. ยกเว้น คุณสามารถขอใบเสนอราคาพร้อมรายการโฆษณาที่ซ้ำกันได้หากเป็น โฆษณา แต่ถ้าคุณมี เว็บไซต์ หลายแห่ง คุณต้องรวมราคาเข้าด้วยกันและแสดงเป็นรายการบรรทัดเดียว นอกจากนี้ หากคุณซื้อเว็บไซต์และมีโฆษณาอยู่แล้วห้ารายการในใบเสนอราคาของคุณ คุณจะต้องให้ส่วนลด 20% บนเว็บไซต์แก่พวกเขา
ฉันได้ยินว่าคุณขว้างแล็ปท็อปผ่านหน้าต่างจากตรงนี้ไป
คุณ สามารถ เขียน if
. จำนวนมาก คำสั่งเพื่อจัดการกับกฎเหล่านี้:
class Quote
attr_accessor :line_items
...
def add_line_item(line_item)
if line_item.kind_of?(Ad)
self.line_items << line_item
elsif line_item.kind_of?(Website)
if @line_items.select {|item| item.kind_of?(Ad) }.length >= 5
# TODO: Put the fractions of a cent into a bank account
# I have set up
line_item.price *= 0.8
end
existing_website = self.line_items.detect { |item| item.kind_of?(Website) }
if existing_website
existing_website.price += line_item.price
else
self.line_items << line_item
end
end
end
end
แต่ฉันคิดว่าเราเห็นด้วยว่ามันแย่มาก คุณจะแก้ให้หายยุ่งได้อย่างไร
คุณสามารถแยกย่อยวิธีการเป็นวิธีการเล็กๆ น้อยๆ ได้หลายอย่าง แต่นั่นก็เหมือนกับการยัดของเล่นทั้งหมดไว้ในตู้เสื้อผ้าเพื่อให้แม่คิดว่าคุณทำความสะอาดห้อง และ kind_of?
s ยังคงรบกวนฉันอยู่มาก
แต่ถ้าคุณเริ่มเห็นสิ่งต่างๆ จาก รายการโฆษณา มุมมองแทนคำพูดของ? ถ้าแทนที่จะ ถาม คุณกำลังติดต่อกับรายการโฆษณาประเภทใดและเพิ่มลงในใบเสนอราคา คุณเพียงแค่ บอก รายการโฆษณาที่จะเพิ่ม ตัวเอง ใบเสนอราคา?
ย้อนกลับวิธีการของคุณ!
วิธีหนึ่งที่ฉันโปรดปรานในการปรับโครงสร้างโค้ดใหม่คือ ลองย้อนกลับผู้โทรและผู้รับสาย นี่คือตัวอย่าง การใช้โค้ดด้านบน:
class Quote
...
def add_line_item(line_item)
line_item.add_to_quote(self)
end
end
class Ad < LineItem
...
def add_to_quote(quote)
quote.line_items << self
end
end
class Website < LineItem
def add_to_quote(quote)
if quote.line_items.select {|item| item.kind_of?(Ad) }.length >= 5
# TODO: Put the fractions of a cent into a bank account
# I have set up
self.price *= 0.8
end
existing_website = quote.line_items.detect { |item| item.kind_of?(Website) }
if existing_website
existing_website.price += self.price
else
quote.line_items << self
end
end
end
มันไม่สมบูรณ์แบบ website.rb
ยังคงต้องการ จำนวนมาก ของความช่วยเหลือในการปรับโครงสร้างใหม่ และฉันไม่พอใจกับการย้อนกลับวิธีการทำให้การห่อหุ้ม line_items
.
แต่คุณได้ขจัดความซับซ้อนชั้นแรกออกไป ตอนนี้คุณสามารถวางโค้ดบน LineItem
หรือ Quote
แล้วแต่ว่าอันไหนเหมาะสมที่สุด LineItem
ออบเจ็กต์สามารถใช้การสืบทอดและมิกซ์อินเพื่อจัดการกับความเหมือนและความแตกต่างระหว่างแต่ละ LineItem
คลาสย่อย นอกจากนี้ การเพิ่ม LineItem
. ใหม่เป็นเรื่องง่าย คลาสย่อยโดยไม่ทำให้ add_line_item
ของคุณบวม วิธีการ
รหัสของคุณสะอาดกว่าเล็กน้อยและยืดหยุ่นกว่ามาก โดยทั่วไปแล้ว ฉันจะเรียกมันว่าชัยชนะ
ตำแหน่งที่คุณอาจไม่ต้องการใช้รูปแบบนี้
มีประโยชน์เช่นเดียวกับ วิธีการย้อนกลับ คือ มีเหตุผลบางประการที่คุณอาจไม่ต้องการใช้รูปแบบนี้:
-
มันสามารถทำลายการห่อหุ้มได้ คุณอาจต้องเปิดเผยแอตทริบิวต์ใน
Quote
วัตถุที่คุณไม่ต้องการเปิดเผยต่อสาธารณะ -
สามารถเพิ่มการมีเพศสัมพันธ์ได้ ทั้ง
Quote
และAd
ตอนนี้จำเป็นต้องรู้เกี่ยวกับกันและกัน และขึ้นอยู่กับว่ามาก พวกเขาจำเป็นต้องรู้จักกัน มันสามารถทำให้โค้ดของคุณมากขึ้น ซับซ้อน -
อาจละเมิดหลักการความรับผิดชอบเดียวใน
Ad
เพราะตอนนี้Ad
มีหน้าที่รู้วิธีเพิ่มตัวเองในQuote
.
คุณมักจะสามารถแก้ไขปัญหาเหล่านี้ได้ แต่คุณควรระวังไว้ เพราะคุณไม่ต้องการการจัดโครงสร้างใหม่เพื่อทำให้โค้ดของคุณแย่ลง!
เหตุใดจึงเป็นหนึ่งในรายการโปรดของฉัน
แม้จะมีปัญหาเหล่านี้ แต่ก็เป็นหนึ่งในการปรับโครงสร้างใหม่ที่ฉันชื่นชอบ รหัสที่ฉันเขียนหลังจากใช้รูปแบบนี้มีแนวโน้มที่จะชัดเจนและมั่นใจมากขึ้น
แต่ถึงแม้จะไม่ใช่ก็ตาม การใช้รูปแบบนี้ทำให้ฉันนึกถึงความสัมพันธ์ระหว่างวัตถุของฉันในวิธีที่ต่างออกไป เมื่อฉันเข้าสู่ "คุณลักษณะนี้แย่มาก ฉันไม่อยากจะเชื่อเลยว่าฉันต้องเขียนโค้ดที่น่ากลัวนี้เพื่อจัดการกับมัน" ร่องลึกนี้ทำให้สมองของฉันมองเห็นวิธีการใหม่ๆ ที่ฉันสามารถแก้ปัญหาเหล่านั้นได้ ทำให้ฉันต้องคิดหาวิธีจัดโครงสร้างโค้ดให้แตกต่างออกไป และมีประโยชน์อย่างเหลือเชื่อ
ลองใช้โค้ดของคุณเอง
เช่นเดียวกับรูปแบบอื่นๆ ที่ฉันชื่นชอบ ตอนแรกฉันเจอ Reversing Method ในรูปแบบแนวทางปฏิบัติที่ดีที่สุดของ Smalltalk และเป็นเครื่องมือที่มีค่านับตั้งแต่นั้นมา
ครั้งต่อไปที่คุณมีปัญหาในการจัดการกับวัตถุที่คล้ายกันซึ่งมีพฤติกรรมแตกต่างกันเล็กน้อย ให้ลองดู! ถ้าคุณชอบรหัสใหม่มากกว่า เก็บไว้ แม้ว่าคุณจะไม่ทำเช่นนั้น แต่ก็จะนำความคิดของคุณไปสู่เส้นทางที่จะนำคุณไปสู่โค้ดที่ดีขึ้น