มันขึ้นอยู่กับความหมายที่แท้จริงของa
, b
และgetProduct
.
วัตถุประสงค์ของ getters คือสามารถเปลี่ยนการใช้งานจริงในขณะที่รักษาอินเทอร์เฟซของวัตถุให้เหมือนเดิม ตัวอย่างเช่นถ้าหนึ่งวันgetA
กลายreturn a + 1;
เป็นการเปลี่ยนแปลงจะแปลเป็นผู้ทะเยอทะยาน
กรณีสถานการณ์จริงบางครั้งซับซ้อนกว่าเขตข้อมูลสำรองคงที่ที่กำหนดผ่านตัวสร้างที่เชื่อมโยงกับทะเยอทะยาน ตัวอย่างเช่นค่าของฟิลด์อาจคำนวณหรือโหลดจากฐานข้อมูลในรหัสต้นฉบับ ในเวอร์ชันถัดไปอาจมีการเพิ่มแคชเพื่อเพิ่มประสิทธิภาพ หากgetProduct
ใช้เวอร์ชันที่คำนวณต่อไปจะไม่ได้รับประโยชน์จากการแคช (หรือผู้ดูแลจะทำการเปลี่ยนแปลงเดียวกันสองครั้ง)
หากgetProduct
ใช้a
กับb
โดยตรงและเหมาะสมที่สุดให้ใช้งาน มิฉะนั้นใช้ getters เพื่อป้องกันปัญหาการบำรุงรักษาในภายหลัง
ตัวอย่างที่หนึ่งจะใช้ getters:
class Product {
public:
Product(ProductId id) : {
price = Money.fromCents(
data.findProductById(id).price,
environment.currentCurrency
)
}
Money getPrice() {
return price;
}
Money getPriceWithRebate() {
return getPrice().applyRebate(rebate); // ← Using a getter instead of a field.
}
private:
Money price;
}
ในขณะที่ผู้ทะเยอทะยานไม่มีตรรกะทางธุรกิจใด ๆ มันก็ไม่ได้ยกเว้นว่าตรรกะในตัวสร้างจะถูกโยกย้ายไปยังผู้ทะเยอทะยานเพื่อหลีกเลี่ยงการทำงานของฐานข้อมูลเมื่อเริ่มต้นวัตถุ:
class Product {
public:
Product(ProductId id) : id(id) { }
Money getPrice() {
return Money.fromCents(
data.findProductById(id).price,
environment.currentCurrency
)
}
Money getPriceWithRebate() {
return getPrice().applyRebate(rebate);
}
private:
const ProductId id;
}
ต่อมาอาจมีการเพิ่มแคช (ใน C #, จะใช้Lazy<T>
, ทำให้รหัสสั้นและง่าย; ฉันไม่รู้ว่ามีเทียบเท่าใน C ++):
class Product {
public:
Product(ProductId id) : id(id) { }
Money getPrice() {
if (priceCache == NULL) {
priceCache = Money.fromCents(
data.findProductById(id).price,
environment.currentCurrency
)
return priceCache;
}
Money getPriceWithRebate() {
return getPrice().applyRebate(rebate);
}
private:
const ProductId id;
Money priceCache;
}
การเปลี่ยนแปลงทั้งสองมุ่งเน้นไปที่ทะเยอทะยานและเขตข้อมูลสำรองรหัสที่เหลือจะไม่ได้รับผลกระทบ หากฉันใช้สนามแทนผู้ทะเยอทะยานgetPriceWithRebate
ฉันก็ต้องสะท้อนการเปลี่ยนแปลงที่นั่นเช่นกัน
ตัวอย่างที่หนึ่งอาจใช้เขตข้อมูลส่วนตัว:
class Product {
public:
Product(ProductId id) : id(id) { }
ProductId getId() const { return id; }
Money getPrice() {
return Money.fromCents(
data.findProductById(id).price, // ← Accessing `id` directly.
environment.currentCurrency
)
}
private:
const ProductId id;
}
ทะเยอทะยานตรงไปตรงมา: มันเป็นตัวแทนโดยตรงของสนามคงที่ (คล้ายกับ C # 's readonly
) ซึ่งไม่คาดว่าจะมีการเปลี่ยนแปลงในอนาคต: โอกาสเป็น ID getter จะไม่กลายเป็นค่าที่คำนวณได้ เพื่อให้ง่ายและเข้าถึงฟิลด์โดยตรง
ข้อดีอีกอย่างคือgetId
อาจถูกลบออกในอนาคตหากปรากฏว่าไม่ได้ใช้งานภายนอก (เช่นในรหัสก่อนหน้า)
const
: ฉันถือว่านั่นหมายความว่าคอมไพเลอร์จะทำการgetId
โทรแบบอินไลน์และช่วยให้คุณสามารถเปลี่ยนแปลงได้ในทิศทางใดทิศทางหนึ่ง (ไม่เช่นนั้นฉันเห็นด้วยกับเหตุผลของคุณอย่างเต็มที่ในการใช้ getters) และในภาษาที่มีไวยากรณ์ของคุณสมบัติก็มีเหตุผลน้อยกว่าที่จะไม่ใช้คุณสมบัติแทนที่จะใช้เขตข้อมูลสำรองโดยตรง