Gözlemci modeli; neyin * değiştiğini bilmek?


10

Klasik bir Observer desen arayüzü tanımlayan iki soyut ders konusu olan Subject and Observer oluşturdum. Gözlemci modelini uygulamak için onlardan türeyim. Bir gözlemci şöyle görünebilir:

void MyClass::Update(Subject *subject)
{
    if(subject == myService_)
    {
        DoSomething();
    }
    else if(subject == myOtherService_)
    {
        DoSomethingElse();
    }
}

Bu iyi ve bana kimin bir şeyi değiştirdiğini söylüyor . Ancak, bana neyin değiştiğini söylemiyor . Bazen bu son çünkü sadece en son veriler için Konu sorgulamak için gidiyorum, ama diğer zamanlarda ben Konu tam olarak ne değiştiğini bilmek gerekir. Java fark onlar muhtemelen ne hakkında ayrıntıları belirtmek için bir notifyObservers () yöntemi ve bir notifyObservers (Object arg) yöntemi var.

Benim durumumda, konu üzerinde birkaç farklı eylemden birinin olup olmadığını bilmem ve belirli bir eylem ise, bu eylemle ilgili bir tamsayı numarasını bilmem gerekiyor.

Yani sorularım:

  1. (Java'nın yaptığı gibi) genel bir bağımsız değişkeni iletmenin C ++ yolu nedir?
  2. Observer en iyi kalıp mı? Belki bir tür olay sistemi?

GÜNCELLEME

Gözlemci kalıbının şablonlaştırılması hakkında konuşan bu makaleyi buldum: Şablonlarla bir Konu / Gözlemci kalıbı uygulama . Bu bana bir argüman tasarlayıp yazamayacağınızı merak ettirdi.

Ben argüman templasyonu hakkında konuşuyor bu yığın taşma sorusunu buldum: Şablon tabanlı Konu Gözlemci desen - static_cast veya dynamic_cast kullanmalıyım . Ancak, OP'nin kimsenin cevaplamadığı bir sorunu var gibi görünüyor.

Yapabileceğim diğer bir şey, bir EventArg nesnesini olduğu gibi almak için Update yöntemini değiştirmek:

void MyClass::Update(Subject *subject, EventArg arg)
{
  ...

Ve sonra belirli argüman verileri için EventArg alt sınıfları oluşturun ve sonra güncelleme yöntemi içinde belirli bir alt sınıfa geri tahmin sanırım.

GÜNCELLEME 2

Ayrıca, bir zaman uyumsuz ileti tabanlı c ++ çerçevesi oluşturma hakkında bir makale bulundu ; Öznenin neyin değiştiği hakkında bilgi vermesini tartışan bölüm 2 .

Şimdi ciddi olarak Boost.Signals kullanmayı düşünüyorum . Kendi gözlemci modelimi kullanmak basitken mantıklıydı, ancak türü ve argümanı değiştirmek karmaşıklaşmaya başlıyor. Ve Boost'un iş parçacığı güvenliğine ihtiyacım olabilir.

GÜNCELLEME 3

Gözlemci modeliyle ilgili bazı ilginç makaleler de buldum:

Herb Sutter'in Gözlemcilerini Genelleştirmek

C ++ 'da Gözlemci Deseni Uygulama - Bölüm 1

Gözlemci Tasarımını Uygulama Deneyimleri (Bölüm 2)

Gözlemci Tasarımını Uygulama Deneyimleri (Bölüm 3)

Ancak, benim uygulama muhtemelen Boost.Signals kullanmaya geçiş yaptım, hangi muhtemelen benim amaç için biraz şişirilmiş olsa da, başarılı bir şekilde çalışıyor. Ve muhtemelen herhangi bir şişkinlik veya hız endişesi önemsizdir.


Vücuttaki sorular gerçekten unvanınıza uymuyor gibi görünüyor. Sorunun özü hangisi?
Nicole

@Renesis: Şu anda yazıma başında kod örneğinde olduğu gibi Observer desen kullanıyorum. Şu anda üzerinde çalıştığım kod için, ben buna göre tepki verebilir böylece özellikle ne değiştiğini bilmek gerekir çıkıyor. Şu anda gözlemci kalıbını (standart olan) uygulamam bu bilgiyi sağlamıyor. Sorum, neyin değiştiği hakkında en iyi bilgiyi nasıl alacağım.
Kullanıcı

@Renesis: Benimkine benzer bir soru soran bir forum dizisi: gamedev.net/topic/497105-observer-pattern
Kullanıcı

Reklam güncellemesi2: Boost.Signals kullanımını kesinlikle destekliyorum. Kendinizi yuvarlamaktan çok daha uygun. Sadece bu görev için daha hafif bir şey istiyorsanız libsigc ++ da vardır (Boost.Signals, Boost'un geri kalanından çok fazla kod kullanır); yine de iş parçacığı için güvenli değildir.
Jan Hudec

Hız sorunları ile ilgili olarak: Özellikle Boost.Signals'ın ne kadar hızlı olduğunu bilmiyorum, ancak bu sadece etrafta uçan çok sayıda olay olduğunda bir endişe ...
Max

Yanıtlar:


4

İster C ++ veya Java, izleyene bir bildirim yapabilirsiniz ait bilgilerle birlikte gelip neyi değiştirilir. NotifyObservers (Object arg) ile aynı yöntemler C ++ 'da da kullanılabilir.

Genel olarak sorun, bir veya birden fazla gözlemciye birden fazla konu gönderilebileceği ve dolayısıyla class argkodlanamamasıdır.

Genellikle, bunu yapmanın en iyi yolu, çeşitli sınıflar için aynı veri türünü oluşturan ancak farklı gözlemlenen sınıflar için değerler farklı olan genel mesaj / jetonlar biçiminde arg yapmaktır. Alternatif olarak, bu tür bildirim değerlerinin tümü, herkes için ortak olan bazı temel sınıflarda sınıftan çıkarılırsa.

Gözlemci modeli için, Arg veri türünün gözlemci ile gözlemci arasında sabit kodlanmamış olması önemlidir - aksi takdirde olayların gelişmesini zorlaştıran bir bağlantıdır.

DÜZENLEME
Gözlemcinin yalnızca gözlemlemesini değil, aynı zamanda neyin değiştiğine bağlı olarak başka birçok görev de yapmasını istiyorsanız, Ziyaretçi desenini de kontrol edebilirsiniz . Ziyaretçi deseninde, gözlemci / ziyaretçi değiştirilen nesneyi çağırır ve bu nedenle sadece değişikliğin ne olduğunu bilmekle kalmaz aynı zamanda üzerinde de çalışabilir


5
Gözlemci argümanı olarak yorumlar, orada olan bir kavrama, sen türü gizlemek nasıl olursa olsun. Aslında , belirli bir türden geçtiğinizden ( veya benzer bir şekilde genel bir şey) geçtiğinizde evrimleşmenin daha zor olduğunu söyleyebilirim , çünkü belirli türle derleme zamanında bir şeyin değiştiğini, genel tür ile gözlemci derlenecek ve çalışmayı durduracaktır, çünkü gözlemci aktarılan gerçek verilerle çalışamayacaktır. Objectvoid *boost::any
Jan Hudec

@JanHudec: Buna katılıyorum, ama bu her bir argüman için belirli bir kerelik bir Gözlemci / Konu alt sınıfı yaptığınız anlamına mı geliyor (yani, her kullanım durumu için)?
Kullanıcı

@JanHudec: bağlantı da sadece bir yoludur. Konunun gözlemciler hakkında hiçbir fikri yok. Evet, gözlemci konuyu bilir, ancak gözlemci düzeni böyle çalışmaz mı?
Kullanıcı

1
@Kullanıcı: Evet, her konu için belirli bir arayüz oluşturuyorum ve her gözlemci gözlemlemesi gereken konuların arayüzlerini uyguluyor. Kullandığım tüm diller, dil veya çerçeve (C # delegeleri, C ++ 11 std::functionBoost boost::function, Gtk + GClosure, python bağlı yöntemler vb.) İçinde yöntem yöntemlerine sahip, bu yüzden sadece uygun imzalarla yöntemleri tanımlayıp sistemden gerçek gözlemci. Bağlanma gerçekten sadece bir yoludur, konu gözlemciler için arayüzü tanımlar, ancak uygulamaları hakkında bir fikri yoktur.
Jan Hudec

0

C ++ 'da "Java Like" genel olay argümanı göndermenin birkaç yolu vardır.

1) Olay bağımsız değişkenini void * olarak bildirin ve olay işleyicide doğru sınıfa aktarın.

2) Olay bağımsız değişkenini yeni bir sınıfa / arabirime (örneğin örneğinize yanıt olarak) işaretçi / ref olarak bildirin

class GenericEventArgument
{
  virtual bool didAction1Happen() = 0;
  virtual int getActionInteger() = 0;
};

Ve gerçek olay argüman sınıflarının bu sınıftan türetilmesini sağlayın.

Şablon tabanlı gözlemci kontrolüyle ilgili sorularınız için

http://www.codeproject.com/Articles/3267/Implementing-a-Subject-Observer-pattern-with-templ


-1

Bunun kanonik isim olup olmadığını bilmiyorum, ama eski Smalltalk günlerimden gözlemlenebilirde neyin değiştiğini tanımlamak için "görünüş" terimini hatırlıyorum.

EventArg (ve alt sınıflandırma) fikriniz kadar karmaşık değildir; sadece gözlemlenebilirden gözlemciye bir dize (hatta bir tamsayı sabiti bile olabilir) geçirir.

Artı: Sadece iki basit yöntem var ( update(observable)veupdateAspect(observable, aspect)

Eksi: Gözlemcinin gözlemlenebilir olandan daha fazla bilgi istemesi gerekebilir (yani, "tamsayı numaranız")

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.