เป็นความคิดที่ดีหรือไม่ที่จะกำหนดฟังก์ชั่นส่วนตัวขนาดใหญ่หนึ่งตัวในคลาสเพื่อรักษาสถานะที่ถูกต้องนั่นคือเพื่ออัพเดทข้อมูลสมาชิกของวัตถุ?


18

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

ฉันพบว่า "ความสอดคล้อง" และ "สถานะเป็นสิ่งที่ชั่วร้าย" เป็นวลีที่เกี่ยวข้องซึ่งได้กล่าวถึงที่นี่: https://en.wikibooks.org/wiki/Object_Oriented_Programming#.22State.22_is_Evil.21

<?php

class CartItem {
  private $price = 0;
  private $shipping = 5; // default
  private $tax = 0;
  private $taxPC = 5; // fixed
  private $totalCost = 0;

  /* private function to update all relevant data members */
  private function updateAllDataMembers() {
    $this->tax =  $this->taxPC * 0.01 * $this->price;
    $this->totalCost = $this->price + $this->shipping + $this->tax;
  }

  public function setPrice($price) {
      $this->price = $price;
      $this->updateAllDataMembers(); /* data is now in valid state */
  }

  public function setShipping($shipping) {
    $this->shipping = $shipping;
    $this->updateAllDataMembers(); /* call this in every setter */
  }

  public function getPrice() {
    return $this->price;
  }
  public function getTaxAmt() {
    return $this->tax;
  }
  public function getShipping() {
    return $this->shipping;
  }
  public function getTotalCost() {
    return $this->totalCost;
  }
}
$i = new CartItem();
$i->setPrice(100);
$i->setShipping(20);
echo "Price = ".$i->getPrice(). 
  "<br>Shipping = ".$i->getShipping().
  "<br>Tax = ".$i->getTaxAmt().
  "<br>Total Cost = ".$i->getTotalCost();

ข้อเสียหรือวิธีที่ดีกว่าในการทำเช่นนี้?

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

แก้ไข: นี่เป็นคำถามที่เกี่ยวข้อง แต่ไม่มีคำแนะนำวิธีปฏิบัติที่ดีที่สุดเกี่ยวกับฟังก์ชั่นใหญ่เดียวเพื่อรักษาสถานะที่ถูกต้อง: /programming/1122346/c-sharp-object-oriented-design-maintaining- ที่ถูกต้องวัตถุรัฐ

EDIT2: แม้ว่าคำตอบของ @ eignesheep นั้นดีที่สุดคำตอบนี้ - /software//a/148109/208591 - เป็นสิ่งที่เติมเต็มบรรทัดระหว่างคำตอบของ @ eigensheep และสิ่งที่ฉันต้องการรู้ - โค้ดควรประมวลผลเท่านั้น และสถานะโกลบอลควรถูกทดแทนโดยการส่งผ่าน DI-enabled ของสถานะระหว่างวัตถุ


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

คำตอบ:


29

ทุกอย่างเท่าเทียมกันคุณควรแสดงค่าคงที่ของคุณในรหัส ในกรณีนี้คุณมีค่าคงที่

$this->tax =  $this->taxPC * 0.01 * $this->price;

ในการแสดงสิ่งนี้ในรหัสของคุณให้ลบตัวแปรสมาชิกภาษีและแทนที่ getTaxAmt () ด้วย

public function getTaxAmt() {
  return $this->taxPC * 0.01 * $this->price;
}

คุณควรทำสิ่งที่คล้ายกันเพื่อกำจัดตัวแปรสมาชิกต้นทุนรวม

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


3
มีหลายภาษาที่มีgettersเพื่อให้ฟังก์ชั่นดังกล่าวแสร้งทำเป็นว่าเป็นคุณสมบัติ สุดยอดของทั้งคู่!
อยากรู้อยากเห็น dannii

จุดที่ยอดเยี่ยม แต่กรณีการใช้งานทั่วไปของฉันคือการดึงรหัสและจัดเก็บข้อมูลไปยังหลายคอลัมน์ในหลายตารางในฐานข้อมูลเชิงสัมพันธ์ (MySQL ส่วนใหญ่) และฉันไม่ต้องการใช้ขั้นตอนการจัดเก็บ (เป็นที่ถกเถียงกันและอีกหัวข้อหนึ่ง นำแนวคิดที่ไม่แปรเปลี่ยนของคุณไปใช้เพิ่มเติมซึ่งหมายความว่าการคำนวณทั้งหมดจะต้อง "ถูกผูกมัด": การgetTotalCost()โทรgetTaxAmt()และอื่น ๆ ซึ่งหมายความว่าเราเก็บสิ่งที่ไม่ได้คำนวณเท่านั้น เราจะย้ายไปสู่การเขียนโปรแกรมการทำงานหรือไม่? สิ่งนี้ยังทำให้การจัดเก็บเอนทิตีที่คำนวณได้ยากในตารางสำหรับการเข้าถึงที่รวดเร็ว ... ต้องการการทดลอง!
site80443

13

ข้อเสียใด ๆ [?]

แน่ใจ วิธีนี้อาศัยทุกคนจำได้เสมอว่าจะทำอะไร วิธีการที่ใช้กับทุกคน & เสมอจะล้มเหลวในบางครั้ง

อาจจะเป็นวิธีที่ดีกว่าในการทำเช่นนี้?

วิธีหนึ่งที่จะหลีกเลี่ยงภาระในการระลึกถึงพิธีคือการคำนวณคุณสมบัติของวัตถุที่ขึ้นอยู่กับคุณสมบัติอื่น ๆ ตามที่จำเป็นตามที่ @ eigensheep แนะนำ

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

$i = new CartItem();
$i->setPrice(100);
$i->setShipping(20);

คุณควรถามตัวเอง รายการรถเข็นที่ไม่มีราคาสมเหตุสมผลหรือไม่? ราคาของสินค้าสามารถเปลี่ยนแปลงได้หรือไม่? หลังจากมันถูกสร้างขึ้น? หลังจากคำนวณภาษีแล้ว? ฯลฯ บางทีคุณควรทำให้CartItemไม่เปลี่ยนรูปและ assig ราคาและการจัดส่งในตัวสร้าง:

$i = new CartItem(100, 20);

รายการสินค้าในรถเข็นไม่มีเหตุผลหากไม่มีสินค้าในรถเข็น?

ถ้าไม่ฉันคาดหวัง$cart->addItem(100, 20)แทน


3
คุณชี้ให้เห็นถึงข้อเสียที่ใหญ่ที่สุด: การพึ่งพาผู้คนที่จดจำในการทำสิ่งต่าง ๆ มักจะเป็นทางออกที่ดี เกี่ยวกับสิ่งเดียวที่คุณสามารถพึ่งพามนุษย์ได้คือพวกเขาจะลืมทำบางสิ่ง
corsiKa

@corsiKlause Ho Ho Ho และ abuzittin ชี้ของแข็งไม่สามารถโต้เถียงกับที่ - คนลืมอย่างสม่ำเสมอ อย่างไรก็ตามรหัสที่ฉันเขียนด้านบนเป็นเพียงตัวอย่างมีกรณีการใช้ที่สำคัญซึ่งสมาชิกข้อมูลบางส่วนได้รับการปรับปรุงในภายหลัง วิธีอื่นที่ฉันเห็นคือทำให้มาตรฐานเป็นปกติ - สร้างคลาสที่สมาชิกข้อมูลที่อัปเดตอิสระอยู่ในคลาสอื่น ๆ และผลักดันความรับผิดชอบของการอัปเดตไปยังอินเทอร์เฟซบางอย่างเพื่อให้โปรแกรมเมอร์คนอื่น ๆ คอมไพเลอร์เตือนคุณว่าคุณต้องเขียนมัน แต่นั่นจะเพิ่มคลาสอีกมาก ...
ไซต์ 80443

1
@ site80443 จากสิ่งที่ฉันเห็นนั่นเป็นแนวทางที่ผิด ลองสร้างแบบจำลองข้อมูลของคุณเพื่อให้มีเฉพาะข้อมูลที่ได้รับการตรวจสอบความถูกต้องเท่านั้น ตัวอย่างเช่นราคาของรายการไม่สามารถเป็นค่าลบได้ขึ้นอยู่กับตัวเองเท่านั้น หากสินค้าถูกลดราคาอย่าแยกส่วนลดเป็นราคา - ตกแต่งด้วยส่วนลดในภายหลัง เก็บ $ 4.99 สำหรับรายการและส่วนลด 20% เป็นนิติบุคคลแยกต่างหากและภาษี 5% เป็นนิติบุคคลอื่น ดูเหมือนจริง ๆ แล้วคุณควรพิจารณารูปแบบการตกแต่งภายในหากตัวอย่างแสดงรหัสชีวิตจริงของคุณ
corsiKa
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.