Mengapa Subjek tidak direkomendasikan dalam Ekstensi Reaktif .NET?

111

Saat ini saya memahami kerangka kerja Ekstensi Reaktif untuk .NET dan saya sedang mengerjakan berbagai sumber pengenalan yang saya temukan (terutama http://www.introtorx.com )

Aplikasi kami melibatkan sejumlah antarmuka perangkat keras yang mendeteksi bingkai jaringan, ini akan menjadi IObservables saya, saya kemudian memiliki berbagai komponen yang akan menggunakan bingkai tersebut atau melakukan beberapa cara mengubah data dan menghasilkan jenis bingkai baru. Juga akan ada komponen lain yang perlu menampilkan setiap bingkai ke-n misalnya. Saya yakin bahwa Rx akan berguna untuk aplikasi kita, namun saya kesulitan dengan detail implementasi untuk antarmuka IObserver.

Sebagian besar (jika tidak semua) sumber daya yang telah saya baca mengatakan bahwa saya tidak boleh mengimplementasikan antarmuka IObservable sendiri, tetapi menggunakan salah satu fungsi atau kelas yang disediakan. Dari penelitian saya, tampaknya membuat a Subject<IBaseFrame>akan memberi saya apa yang saya butuhkan, saya akan memiliki utas tunggal yang membaca data dari antarmuka perangkat keras dan kemudian memanggil fungsi OnNext dari Subject<IBaseFrame>instance saya . Komponen IObserver yang berbeda kemudian akan menerima notifikasi dari Subjek tersebut.

Kebingungan saya datang dari saran yang diberikan di lampiran tutorial ini di mana dikatakan:

Hindari penggunaan jenis subjek. Rx secara efektif merupakan paradigma pemrograman fungsional. Menggunakan subjek berarti kita sekarang mengelola status, yang berpotensi bermutasi. Berurusan dengan status mutasi dan pemrograman asynchronous pada saat yang sama sangat sulit dilakukan dengan benar. Selain itu, banyak operator (metode ekstensi) telah ditulis dengan cermat untuk memastikan bahwa masa pakai langganan dan urutan yang benar dan konsisten dipertahankan; saat Anda memperkenalkan subjek, Anda dapat memecahkannya. Rilis mendatang mungkin juga melihat penurunan performa yang signifikan jika Anda menggunakan subjek secara eksplisit.

Aplikasi saya cukup kritis terhadap kinerja, saya jelas akan menguji kinerja penggunaan pola Rx sebelum masuk ke kode produksi; namun saya khawatir bahwa saya melakukan sesuatu yang bertentangan dengan semangat kerangka kerja Rx dengan menggunakan kelas Subjek dan versi kerangka kerja yang akan datang akan merusak kinerja.

Adakah cara yang lebih baik untuk melakukan apa yang saya inginkan? Rangkaian polling perangkat keras akan terus berjalan baik ada pengamat atau tidak (buffer HW akan mencadangkan jika tidak), jadi ini adalah urutan yang sangat panas. Saya kemudian perlu meneruskan frame yang diterima ke beberapa pengamat.

Saran apa pun akan sangat dihargai.

Anthony
sumber
1
Ini benar-benar membantu pemahaman saya tentang subjek, saya hanya memikirkan tentang bagaimana menggunakannya dalam aplikasi saya. Saya tahu bahwa mereka adalah hal yang benar - Saya memiliki pipeline komponen yang sangat berorientasi pada push dan saya perlu melakukan semua jenis pemfilteran dan pemanggilan pada thread UI untuk ditampilkan di GUI serta buffering frame yang diterima terakhir, dll. dll - Saya hanya perlu memastikan bahwa saya melakukannya dengan benar pada kali pertama!
Anthony

Jawaban:

70

Oke, Jika kita mengabaikan cara dogmatis saya dan mengabaikan "subjek itu baik / buruk" secara bersamaan. Mari kita lihat ruang masalahnya.

Saya yakin Anda juga memiliki 1 dari 2 gaya sistem yang Anda butuhkan.

  1. Sistem memunculkan acara atau panggilan kembali ketika pesan tiba
  2. Anda perlu melakukan polling pada sistem untuk melihat apakah ada pesan untuk diproses

Untuk opsi 1, mudah, kita cukup membungkusnya dengan metode FromEvent yang sesuai dan selesai. Ke Pub!

Untuk opsi 2, sekarang kita perlu mempertimbangkan bagaimana kita melakukan polling ini dan bagaimana melakukannya dengan efisien. Juga ketika kita mendapatkan nilainya, bagaimana kita mempublikasikannya?

Saya akan membayangkan bahwa Anda menginginkan utas khusus untuk pemungutan suara. Anda tidak ingin pembuat kode lain memalu ThreadPool / TaskPool dan meninggalkan Anda dalam situasi kelaparan ThreadPool. Atau Anda tidak ingin kerumitan peralihan konteks (saya kira). Jadi asumsikan kita memiliki utas kita sendiri, kita mungkin akan memiliki semacam loop While / Sleep yang kita duduki untuk melakukan polling. Ketika pemeriksaan menemukan beberapa pesan, kami menerbitkannya. Semua ini terdengar sempurna untuk Observable.Create. Sekarang kita mungkin tidak bisa menggunakan loop While karena itu tidak akan memungkinkan kita untuk mengembalikan Disposable untuk memungkinkan pembatalan. Untungnya Anda telah membaca keseluruhan buku sehingga paham dengan penjadwalan rekursif!

Saya membayangkan sesuatu seperti ini bisa berhasil. #Tidak diuji

public class MessageListener
{
    private readonly IObservable<IMessage> _messages;
    private readonly IScheduler _scheduler;

    public MessageListener()
    {
        _scheduler = new EventLoopScheduler();

        var messages = ListenToMessages()
                                    .SubscribeOn(_scheduler)
                                    .Publish();

        _messages = messages;
        messages.Connect();
    }

    public IObservable<IMessage> Messages
    {
        get {return _messages;}
    }

    private IObservable<IMessage> ListenToMessages()
    {
        return Observable.Create<IMessage>(o=>
        {
                return _scheduler.Schedule(recurse=>
                {
                    try
                    {           
                        var messages = GetMessages();
                        foreach (var msg in messages)
                        {
                            o.OnNext(msg);
                        }   
                        recurse();
                    }
                    catch (Exception ex)
                    {
                        o.OnError(ex);
                    }                   
                });
        });
    }

    private IEnumerable<IMessage> GetMessages()
    {
         //Do some work here that gets messages from a queue, 
         // file system, database or other system that cant push 
         // new data at us.
         // 
         //This may return an empty result when no new data is found.
    }
}

Alasan saya sangat tidak menyukai Subjek, adalah karena biasanya pengembang tidak memiliki desain yang jelas tentang masalah tersebut. Retas subjek, aduk di sana-sini dan di mana-mana, dan kemudian biarkan pengembang dukungan yang buruk menebak di WTF yang sedang terjadi. Ketika Anda menggunakan metode Buat / Hasilkan dll, Anda melokalkan efek pada urutan. Anda dapat melihat semuanya dalam satu metode dan Anda tahu tidak ada orang lain yang memberikan efek samping yang buruk. Jika saya melihat bidang subjek, sekarang saya harus mencari semua tempat di kelas yang sedang digunakan. Jika beberapa MFer mengeksposnya secara publik, maka semua taruhan dibatalkan, siapa yang tahu bagaimana urutan ini digunakan! Async / Concurrency / Rx sulit. Anda tidak perlu membuatnya lebih sulit dengan membiarkan efek samping dan pemrograman kausalitas semakin memusingkan kepala Anda.

Lee Campbell
sumber
10
Saya baru saja membaca jawaban ini sekarang tetapi saya merasa saya harus menunjukkan bahwa saya tidak akan pernah mempertimbangkan untuk mengekspos antarmuka Subjek! Saya menggunakannya untuk menyediakan implementasi IObservable <> dalam kelas tertutup (yang mengekspos IObservable <>). Saya pasti bisa mengerti mengapa mengekspos antarmuka Subjek <> akan menjadi Bad Thing ™
Anthony
hei, maaf sudah tebal, tapi saya tidak begitu mengerti kode Anda. apa yang ListenToMessages () dan GetMessages () lakukan dan kembalikan?
pengguna10479
1
Untuk proyek pribadi Anda @jeromerg, ini mungkin baik-baik saja. Namun dalam pengalaman saya pengembang berjuang dengan WPF, MVVM, unit pengujian desain GUI dan kemudian memasukkan Rx dapat membuat segalanya lebih rumit. Saya telah mencoba pola BehaviourSubject-as-a-property. Namun saya menemukan bahwa itu jauh lebih dapat diadopsi untuk orang lain jika kita menggunakan properti INPC standar dan kemudian menggunakan metode Ekstensi sederhana untuk mengubahnya menjadi IObservable. Selain itu, Anda memerlukan pengikatan WPF khusus untuk bekerja dengan subjek perilaku Anda. Sekarang tim Anda yang malang harus mempelajari WPF, MVVM, Rx, dan kerangka kerja baru Anda juga.
Lee Campbell
2
@LeeCampbell, untuk memasukkannya ke dalam contoh kode Anda, cara normalnya adalah MessageListener dibangun oleh sistem (Anda mungkin entah bagaimana mendaftarkan nama kelas), dan Anda diberi tahu bahwa sistem kemudian akan memanggil OnCreate () dan OnGoodbye (), dan akan memanggil message1 (), message2 (), dan message3 () saat pesan dibuat. Sepertinya messageX [123] akan memanggil OnNext tentang subjek, tetapi adakah cara yang lebih baik?
James Moore
1
@JamesMoore karena hal-hal ini lebih mudah dijelaskan dengan contoh konkret. Jika Anda mengetahui aplikasi Android Open Source yang menggunakan Rx dan Subjects, mungkin saya bisa meluangkan waktu untuk melihat apakah saya bisa memberikan cara yang lebih baik. Saya mengerti bahwa tidak terlalu membantu untuk berdiri di atas tumpuan dan mengatakan bahwa Subjek itu buruk. Tapi saya pikir hal-hal seperti IntroToRx, RxCookbook dan ReactiveTrader semuanya memberikan berbagai tingkatan contoh bagaimana menggunakan Rx.
Lee Campbell
38

Secara umum Anda harus menghindari penggunaan Subject, namun untuk hal yang Anda lakukan di sini saya pikir mereka bekerja dengan cukup baik. Saya mengajukan pertanyaan serupa ketika saya menemukan pesan "hindari subjek" di tutorial Rx.

Mengutip Dave Sexton (dari Rxx)

"Subjek adalah komponen stateful dari Rx. Mereka berguna saat Anda perlu membuat observasi seperti peristiwa sebagai kolom atau variabel lokal."

Saya cenderung menggunakannya sebagai titik masuk ke Rx. Jadi jika saya memiliki beberapa kode yang perlu mengatakan 'sesuatu terjadi' (seperti yang Anda miliki), saya akan menggunakan Subjectdan memanggil OnNext. Kemudian tunjukkan itu sebagai IObservablelangganan orang lain (Anda dapat menggunakan AsObservable()subjek Anda untuk memastikan tidak ada yang dapat mentransmisikan ke Subjek dan mengacaukan semuanya).

Anda juga dapat mencapai ini dengan acara dan penggunaan .NET FromEventPattern, tetapi jika saya hanya akan mengubah acara menjadi sebuah IObservable, saya tidak melihat manfaat memiliki acara daripada Subject(yang mungkin berarti saya kehilangan sesuatu disini)

Namun, yang harus Anda hindari cukup kuat adalah berlangganan IObservabledengan a Subject, yaitu jangan meneruskan a Subjectke dalam IObservable.Subscribemetode.

Wilka
sumber
Mengapa Anda membutuhkan pernyataan sama sekali? Seperti yang ditunjukkan oleh jawaban saya, jika Anda memecah masalah menjadi beberapa bagian, Anda tidak benar-benar harus mengelola status sama sekali. Subjek tidak boleh digunakan dalam kasus ini.
casperOne
8
@casperOne Anda tidak memerlukan status di luar Subjek <T> atau peristiwa (yang keduanya memiliki kumpulan hal-hal untuk dipanggil, pengamat, atau penangan peristiwa). Saya lebih suka menggunakan Subjek jika satu-satunya alasan untuk menambahkan acara adalah membungkusnya dengan FromEventPattern. Selain dari perubahan skema pengecualian, yang mungkin penting bagi Anda, saya tidak melihat manfaat untuk menghindari Subjek dengan cara ini. Sekali lagi, saya mungkin melewatkan sesuatu yang lain di sini yang acara tersebut lebih disukai daripada Subjek. Penyebutan negara bagian hanyalah sebagian dari kutipan, dan sepertinya lebih baik membiarkannya masuk. Mungkin lebih jelas tanpa bagian itu?
Wilka
@casperOne - tetapi Anda juga tidak boleh membuat acara hanya untuk membungkusnya dengan FromEventPattern. Itu jelas ide yang buruk.
James Moore
3
Saya telah menjelaskan kutipan saya lebih dalam di posting blog ini .
Dave Sexton
Saya cenderung menggunakannya sebagai titik masuk ke Rx. Ini tepat sekali bagi saya. Saya mengalami situasi di mana ada API yang ketika dipanggil menghasilkan peristiwa yang ingin saya lewati melalui pipeline pemrosesan reaktif. Subjek adalah jawaban untuk saya, karena FromEventPattern sepertinya tidak ada di RxJava AFAICT.
scorpiodawg
31

Seringkali ketika Anda mengelola sebuah Subjek, Anda sebenarnya hanya mengimplementasikan ulang fitur-fitur yang sudah ada di Rx, dan mungkin dengan cara yang tidak sekuat, sesederhana dan dapat diperluas.

Saat Anda mencoba menyesuaikan beberapa aliran data asinkron ke Rx (atau membuat aliran data asinkron dari salah satu yang saat ini tidak asinkron), kasus yang paling umum biasanya:

  • Sumber data adalah sebuah peristiwa : Seperti yang dikatakan Lee, ini adalah kasus yang paling sederhana: gunakan FromEvent dan pergi ke pub.

  • Sumber data berasal dari operasi sinkron dan Anda menginginkan pembaruan yang disurvei , (mis. Layanan web atau panggilan database): Dalam hal ini Anda dapat menggunakan pendekatan yang disarankan Lee, atau untuk kasus sederhana, Anda dapat menggunakan sesuatu seperti Observable.Interval.Select(_ => <db fetch>). Anda mungkin ingin menggunakan DistinctUntilChanged () untuk mencegah publikasi pembaruan ketika tidak ada yang berubah dalam data sumber.

  • Sumber data adalah sejenis api asinkron yang memanggil callback Anda : Dalam hal ini, gunakan Observable.Create untuk menghubungkan callback Anda untuk memanggil OnNext / OnError / OnComplete pada pengamat.

  • Sumber data adalah panggilan yang memblokir hingga data baru tersedia (misalnya, beberapa operasi pembacaan soket sinkron): Dalam kasus ini, Anda dapat menggunakan Observable.Create untuk menggabungkan kode penting yang membaca dari soket dan menerbitkannya ke Observer.OnNext saat data dibaca. Ini mungkin serupa dengan apa yang Anda lakukan dengan Subjek.

Menggunakan Observable.Create vs membuat kelas yang mengelola Subjek cukup setara dengan menggunakan kata kunci hasil vs membuat seluruh kelas yang mengimplementasikan IEnumerator. Tentu saja, Anda dapat menulis IEnumerator agar menjadi warga negara yang bersih dan sebaik kode hasil, tetapi mana yang lebih baik dikemas dan terasa desainnya lebih rapi? Hal yang sama berlaku untuk Observable. Buat vs mengelola Subjek.

Observable.Create memberi Anda pola yang bersih untuk pengaturan yang lambat dan pembongkaran yang bersih. Bagaimana Anda mencapai ini dengan kelas yang membungkus sebuah Subjek? Anda memerlukan semacam metode Mulai ... bagaimana Anda tahu kapan harus memanggilnya? Atau apakah Anda selalu memulainya, bahkan saat tidak ada yang mendengarkan? Dan ketika Anda sudah selesai, bagaimana Anda membuatnya berhenti membaca dari socket / polling database, dll? Anda harus memiliki semacam metode Berhenti, dan Anda masih harus memiliki akses tidak hanya ke IObservable langganan Anda, tetapi kelas yang membuat Subjek di tempat pertama.

Dengan Observable.Create, semuanya dibungkus di satu tempat. Badan Observable.Create tidak berjalan sampai seseorang berlangganan, jadi jika tidak ada yang berlangganan, Anda tidak pernah menggunakan sumber daya Anda. Dan Observable.Create mengembalikan Disposable yang dapat dengan bersih mematikan resource / callback Anda, dll - ini dipanggil saat Observer berhenti berlangganan. Umur sumber daya yang Anda gunakan untuk menghasilkan Observable terkait erat dengan masa Observable itu sendiri.

Niall Connaughton
sumber
1
Penjelasan yang sangat jelas tentang Observable.Create. Terima kasih!
Evan Moran
1
Saya masih memiliki kasus di mana saya menggunakan subjek, di mana objek broker mengekspos hal yang dapat diamati (katakanlah itu hanya properti yang dapat diubah). Komponen yang berbeda akan memanggil broker yang memberi tahu ketika properti itu berubah (dengan panggilan metode), dan metode itu melakukan OnNext. Konsumen berlangganan. Saya pikir saya akan menggunakan BehaviorSubject dalam kasus ini, apakah itu sesuai?
Frank Schwieterman
1
Tergantung situasinya. Desain Rx yang baik cenderung mengubah sistem menuju arsitektur async / reaktif. Mungkin sulit untuk mengintegrasikan komponen kecil kode reaktif dengan sistem yang sangat penting. Solusi bantuan pita adalah menggunakan Subjek untuk mengubah tindakan penting (panggilan fungsi, kumpulan properti) menjadi peristiwa yang dapat diamati. Kemudian Anda berakhir dengan kantong kecil kode reaktif dan tidak ada "aha!" Yang nyata. saat. Mengubah desain untuk memodelkan aliran data dan menanggapinya biasanya memberikan desain yang lebih baik, tetapi ini adalah perubahan yang meluas dan memerlukan perubahan pola pikir dan dukungan tim.
Niall Connaughton
1
Saya akan menyatakan di sini (sebagai Rx tidak berpengalaman) bahwa: Dengan menggunakan Subjek Anda dapat memasuki dunia Rx dalam aplikasi penting yang tumbuh dan perlahan mengubahnya. Juga untuk mendapatkan pengalaman pertama .... dan tentunya kemudian ubah kode Anda seperti semestinya dari awal (lol). Tapi untuk memulainya, saya pikir akan bermanfaat jika menggunakan subjek.
Robetto
9

Teks blok yang dikutip cukup banyak menjelaskan mengapa Anda tidak boleh menggunakan Subject<T>, tetapi untuk membuatnya lebih sederhana, Anda menggabungkan fungsi pengamat dan yang dapat diamati, sambil memasukkan semacam status di antaranya (apakah Anda merangkum atau memperluas).

Di sinilah Anda mengalami masalah; tanggung jawab ini harus terpisah dan berbeda satu sama lain.

Karena itu, dalam kasus khusus Anda , saya sarankan Anda memecah kekhawatiran Anda menjadi bagian-bagian yang lebih kecil.

Pertama, Anda memiliki utas Anda yang panas, dan selalu memantau perangkat keras untuk sinyal untuk menaikkan pemberitahuan. Bagaimana Anda biasanya melakukan ini? Acara . Jadi mari kita mulai dengan itu.

Mari kita tentukan EventArgsapakah acara Anda akan diaktifkan.

// The event args that has the information.
public class BaseFrameEventArgs : EventArgs
{
    public BaseFrameEventArgs(IBaseFrame baseFrame)
    {
        // Validate parameters.
        if (baseFrame == null) throw new ArgumentNullException("IBaseFrame");

        // Set values.
        BaseFrame = baseFrame;
    }

    // Poor man's immutability.
    public IBaseFrame BaseFrame { get; private set; }
}

Sekarang, kelas yang akan mengaktifkan acara tersebut. Catatan, ini bisa menjadi kelas statis (karena Anda selalu memiliki utas yang berjalan memantau buffer perangkat keras), atau sesuatu yang Anda panggil sesuai permintaan yang berlangganan itu . Anda harus memodifikasi ini sebagaimana mestinya.

public class BaseFrameMonitor
{
    // You want to make this access thread safe
    public event EventHandler<BaseFrameEventArgs> HardwareEvent;

    public BaseFrameMonitor()
    {
        // Create/subscribe to your thread that
        // drains hardware signals.
    }
}

Jadi sekarang Anda memiliki kelas yang mengekspos acara. Dapat diamati bekerja dengan baik dengan acara. Sedemikian rupa sehingga ada dukungan kelas satu untuk mengonversi aliran peristiwa (pikirkan aliran peristiwa sebagai beberapa pengaktifan peristiwa) menjadi IObservable<T>implementasi jika Anda mengikuti pola peristiwa standar, melalui metode statisFromEventPattern di Observablekelas .

Dengan sumber acara Anda, dan FromEventPatternmetode, kita dapat membuat dengan IObservable<EventPattern<BaseFrameEventArgs>>mudah ( EventPattern<TEventArgs>kelas mewujudkan apa yang Anda lihat dalam acara .NET, terutama, sebuah instance yang diturunkan dari EventArgsdan objek yang mewakili pengirim), seperti:

// The event source.
// Or you might not need this if your class is static and exposes
// the event as a static event.
var source = new BaseFrameMonitor();

// Create the observable.  It's going to be hot
// as the events are hot.
IObservable<EventPattern<BaseFrameEventArgs>> observable = Observable.
    FromEventPattern<BaseFrameEventArgs>(
        h => source.HardwareEvent += h,
        h => source.HardwareEvent -= h);

Tentu saja, Anda menginginkan IObservable<IBaseFrame>, tapi itu mudah, menggunakan Selectmetode ekstensi pada Observablekelas untuk membuat proyeksi (seperti yang Anda lakukan di LINQ, dan kita bisa membungkus semua ini dengan metode yang mudah digunakan):

public IObservable<IBaseFrame> CreateHardwareObservable()
{
    // The event source.
    // Or you might not need this if your class is static and exposes
    // the event as a static event.
    var source = new BaseFrameMonitor();

    // Create the observable.  It's going to be hot
    // as the events are hot.
    IObservable<EventPattern<BaseFrameEventArgs>> observable = Observable.
        FromEventPattern<BaseFrameEventArgs>(
            h => source.HardwareEvent += h,
            h => source.HardwareEvent -= h);

    // Return the observable, but projected.
    return observable.Select(i => i.EventArgs.BaseFrame);
}
casperOne
sumber
7
Terima kasih atas tanggapan Anda @casperOne, ini adalah pendekatan awal saya tetapi rasanya "salah" untuk menambahkan acara hanya agar saya bisa membungkusnya dengan Rx. Saat ini saya menggunakan delegasi (dan ya, saya tahu bahwa itulah tepatnya peristiwa itu!) Agar sesuai dengan kode yang digunakan untuk memuat dan menyimpan konfigurasi, ini harus dapat membangun kembali pipa komponen dan sistem delegasi memberi saya paling banyak fleksibilitas. Rx membuat saya pusing di area ini sekarang tetapi kekuatan dari segala sesuatu yang lain dalam kerangka membuat pemecahan masalah konfigurasi sangat berharga.
Anthony
@Anthony Jika Anda bisa mendapatkan sampel kodenya untuk bekerja, bagus, tapi seperti yang saya komentari, itu tidak masuk akal. Mengenai perasaan "salah", saya tidak tahu mengapa membagi hal-hal menjadi bagian logis tampak "salah", tetapi Anda belum memberikan detail yang cukup di posting asli Anda untuk menunjukkan cara terbaik menerjemahkan ini IObservable<T>sebagai tidak ada informasi tentang bagaimana Anda ' re saat ini memberi isyarat dengan informasi yang diberikan.
casperOne
@casperOne Menurut pendapat Anda, apakah penggunaan Subjek sesuai untuk Bus Pesan / Agregator Acara?
kitsune
1
@ Kitsune Tidak, saya tidak mengerti mengapa mereka melakukannya. Jika Anda berpikir "pengoptimalan", Anda harus menanyakan pertanyaan apakah itu masalahnya atau tidak, apakah Anda mengukur Rx sebagai penyebab masalah?
casperOne
2
Saya setuju di sini dengan casperOne bahwa memecah masalah adalah ide yang bagus. Saya ingin menunjukkan, bahwa jika Anda menggunakan pola Hardware to Event to Rx, Anda kehilangan semantik kesalahan. Koneksi atau sesi yang hilang, dll. Tidak akan diungkapkan kepada konsumen. Sekarang konsumen tidak dapat memutuskan apakah mereka ingin mencoba lagi, memutuskan sambungan, berlangganan ke urutan lain atau yang lainnya.
Lee Campbell
0

Ini buruk untuk menggeneralisasi bahwa Subjek tidak baik digunakan untuk antarmuka publik. Meskipun memang benar, bahwa ini bukan cara pendekatan pemrograman reaktif seharusnya terlihat, namun secara definitif merupakan opsi perbaikan / pemfaktoran ulang yang baik untuk kode klasik Anda.

Jika Anda memiliki properti normal dengan aksesor kumpulan publik dan Anda ingin memberi tahu tentang perubahan, tidak ada yang melarang menggantinya dengan BehaviorSubject. INPC atau acara tambahan lainnya tidak begitu bersih dan secara pribadi membuat saya lelah. Untuk tujuan ini, Anda dapat dan harus menggunakan BehaviorSubjects sebagai properti publik, bukan properti normal, dan membuang INPC atau peristiwa lainnya.

Selain itu, antarmuka Subjek membuat pengguna antarmuka Anda lebih sadar tentang fungsionalitas properti Anda dan lebih cenderung untuk berlangganan daripada hanya mendapatkan nilainya.

Ini adalah yang terbaik untuk digunakan jika Anda ingin orang lain mendengarkan / berlangganan perubahan properti.

Felix Keil
sumber