Bir sınıfta geçerli durumu korumak, yani nesnenin veri üyelerini güncellemek için büyük bir özel işlev tanımlamak iyi bir fikir mi?


18

Aşağıdaki kodda bir e-ticaret sitesinde basit bir tek öğe satın alma kullanılmasına rağmen, genel sorum, bir nesnenin verilerini her zaman geçerli durumda tutmak için tüm veri üyelerini güncellemektir.

Burada tartışılan alakalı ifadeler olarak "tutarlılık" ve "durum kötü" buldum: 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();

Herhangi bir dezavantaj, ya da belki de bunu yapmanın daha iyi yolları?

İlişkisel bir veritabanı tarafından desteklenen gerçek dünya uygulamalarında tekrarlanan bir sorundur ve saklı yordamları tüm doğrulamayı veritabanına itmek için yoğun olarak kullanmazsanız. Ben veri deposu sadece veri depolamak gerektiğini düşünüyorum, kod ise tüm çalışma zamanı durumunu korumak iş yapmak gerekir.

EDIT: Bu ilgili bir soru, ancak geçerli durumunu korumak için tek bir büyük işlevi ile ilgili en iyi uygulama önerisi yok: /programming/1122346/c-sharp-object-oriented-design-maintaining- geçerli-nesne-devlet

EDIT2: @ eignesheep'in yanıtı en iyisi olmasına rağmen, bu cevap - /software//a/148109/208591 - @ eigensheep'in yanıtı ve bilmek istediklerim arasındaki çizgileri dolduran şeydir - kod yalnızca işlenmelidir, ve küresel durum, DI-etkin durumun nesneler arasında geçişi ile değiştirilmelidir.


Yüzde değişkenleri olmaktan kaçınırım. Kullanıcıdan bir yüzdeyi kabul edebilir veya bir kullanıcıya gösterebilirsiniz, ancak program değişkenleri oranlarsa yaşam çok daha iyidir.
kevin cline

Yanıtlar:


29

Diğer her şey eşit olduğunda, değişmezlerinizi kodla ifade etmelisiniz. Bu durumda değişmez var

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

Bunu kodunuzda ifade etmek için vergi üyesi değişkenini kaldırın ve getTaxAmt () ile değiştirin

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

Toplam maliyet üyesi değişkeninden kurtulmak için benzer bir şey yapmalısınız.

Değişmezlerinizi kodunuzda ifade etmek hataların önlenmesine yardımcı olabilir. Orijinal kodda, setPrice veya setShipping çağrılmadan önce kontrol edilirse toplam maliyet yanlıştır.


3
Birçok dilde alıcılar vardır, böylece bu işlevler özellik gibi davranır. Her ikisinin de en iyisi!
curiousdannii

Mükemmel nokta, ama benim genel kullanım durum nerede kod alır ve ilişkisel bir veritabanında (çoğunlukla MySQL) birden çok tabloda birden çok sütun veri depolar ve saklı yordamlar (tartışmalı ve kendi başına başka bir konu) kullanmak istemiyorum. Kod içinde değişmezler fikrinizi daha ileriye götürmek, tüm hesaplamaların "zincirlenmesi" gerektiği anlamına gelir: getTotalCost()çağrılar getTaxAmt()vb. Bu sadece hesaplanmayan şeyleri sakladığımız anlamına gelir . Biraz fonksiyonel programlamaya doğru ilerliyor muyuz? Bu aynı zamanda hızlı erişim için hesaplanan varlıkların tablolarda depolanmasını zorlaştırır ... Deneye ihtiyaç var!
site80443

13

Herhangi bir dezavantaj [?]

Elbette. Bu yöntem, her zaman bir şeyler yapmayı hatırlayan herkese dayanır . Herkese güvenen herhangi bir yöntem bazen başarısızlığa mahkumdur .

belki de bunu yapmanın daha iyi yolları?

Töreni hatırlama yükünden kaçınmanın bir yolu, @eigensheep'in önerdiği gibi, gerektiğinde diğer özelliklere bağlı olan nesnenin özelliklerini hesaplamaktır.

Diğeri, alışveriş sepetini değiştirilemez hale getirmek ve yapıcı / fabrika yönteminde hesaplamaktır. Nesneyi değişmez kılsanız bile normalde "gerektiği gibi hesapla" yöntemiyle devam edersiniz. Ancak hesaplama çok zaman alıcıysa ve birçok kez okunacaksa; "oluşturma sırasında hesapla" seçeneğini belirleyebilirsiniz.

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

Kendinize sormalısınız; Ücreti olmayan bir alışveriş sepeti mantıklı mı? Bir ürünün fiyatı değişebilir mi? Oluşturulduktan sonra? Vergi hesaplandıktan sonra? vs Belki CartItemyapıcıda değişmez ve fiyat ve nakliye yapmak gerekir :

$i = new CartItem(100, 20);

Bir alışveriş sepeti, ait olduğu alışveriş sepeti olmadan anlamlı mı?

Değilse, $cart->addItem(100, 20)onun yerine beklerdim .


3
En büyük dezavantaja dikkat çekiyorsunuz: bir şeyler yapmayı hatırlayan insanlara güvenmek nadiren iyi bir çözümdür. İnsana güvenebileceğiniz tek şey, bir şey yapmayı unutacaklarıdır.
corsiKa

@corsiKlause Ho Ho Ho ve katı nokta, bununla tartışamazlar - insanlar her zaman unuturlar . Ancak, yukarıda yazdığım kod sadece bir örnektir, bazı veri üyelerinin daha sonra güncellendiği önemli kullanım durumları vardır. Gördüğüm diğer bir yol daha da normalleştirmektir - bağımsız olarak güncellenen veri üyeleri diğer sınıflarda olacak ve güncelleştirme sorumluluğunu bazı arayüzlere itecek şekilde sınıflar yapmak - böylece diğer programcılar (ve bir süre sonra kendiniz) bir yöntem yazmak zorunda - derleyici yazmanız gerektiğini hatırlatır. Ama bu çok daha fazla sınıf ekler ...
site80443 25:15

1
@ site80443 Gördüklerime dayanarak, bu yanlış yaklaşım. Verilerinizi, yalnızca kendisine karşı onaylanan veriler dahil edilecek şekilde modellemeye çalışın. Örneğin, bir ürünün fiyatı negatif olamaz, yalnızca kendine güvenir. Bir öğe indirim yapılmışsa, indirimi fiyata dahil etmeyin - daha sonra indirim ile süsleyin. Öğe için 4,99 ABD doları ve ayrı bir varlık olarak% 20 indirim ve başka bir varlık olarak% 5 vergi depolayın. Örnekler gerçek hayat kodunuzu temsil ediyorsa Dekoratör desenini göz önünde bulundurmanız gerekir.
corsiKa
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.