Це залежить від фактичного значення a
, b
і getProduct
.
Метою геттерів є можливість змінити фактичну реалізацію, зберігаючи інтерфейс об'єкта тим самим. Наприклад, якщо один день getA
стає return a + 1;
, зміна локалізується на геттера.
Реальні випадки сценарію іноді складніші, ніж постійне поле резервного копіювання, призначене через конструктор, пов'язаний з геттером. Наприклад, значення поля може бути обчислено або завантажено з бази даних в оригінальній версії коду. У наступній версії може бути додано кешування для оптимізації продуктивності. Якщо getProduct
продовжувати використовувати обчислювану версію, кешування не піде на користь (або сервіс виконає таку ж зміну двічі).
Якщо це має ідеальний сенс для getProduct
використання a
та b
безпосередньо, використовуйте їх. В іншому випадку використовуйте геттери, щоб запобігти проблемам з технічним обслуговуванням пізніше.
Приклад, де можна було б отримати 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;
}
Хоча на даний момент, getter не містить жодної бізнес-логіки, не виключено, що логіка в конструкторі буде перенесена на getter, щоб уникнути виконання роботи з базою даних при ініціалізації об'єкта:
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 ніколи не стане обчисленим значенням. Тому нехай це буде просто та безпосередньо отримуйте доступ до поля.
Ще одна перевага полягає в тому, що він getId
може бути видалений у майбутньому, якщо виявиться, що він не використовується зовні (як у попередньому фрагменті коду).
const
: я припускаю, що це означає, що компілятор вgetId
будь-якому випадку вбуде вкладений дзвінок, і це дозволяє вам вносити зміни в будь-якому напрямку. ( В іншому випадку я повністю згоден з вашими причинами для використання видобувачів.) І в мовах , які надають синтаксис властивостей, є навіть менше причини не використовувати властивість , а не поле підкладки безпосередньо.