Apakah ini bau kode jika suatu objek mengetahui banyak pemiliknya?

9

Dalam aplikasi Delphi 2007 kami, kami menggunakan banyak konstruksi berikut

FdmBasic:=TdmBasicData(FindOwnerClass(AOwner,TdmBasicData));

FindOwnerClass melakukan perjalanan hierarki pemilik komponen saat ini ke atas untuk menemukan kelas tertentu (dalam contoh TdmBasicData). Objek yang dihasilkan disimpan dalam variabel Field FdmBasic. Kami menggunakan ini terutama untuk melewatkan datamodules.

Contoh: Saat membuat laporan, data yang dihasilkan dikompresi dan disimpan dalam bidang gumpalan tabel yang diakses melalui datamodule TdmReportBaseData. Dalam modul terpisah dari aplikasi kami, ada fungsi untuk menampilkan data dari laporan dalam formulir Paged menggunakan ReportBuilder. Kode utama modul ini (TdmRBReport), menggunakan kelas TRBTempdatabase untuk mengonversi data gumpalan terkompresi menjadi tabel yang berbeda yang dapat digunakan dalam reportdesign runtime reportdesigner runtime Reportbuilder. TdmRBReport memiliki akses ke TdmReportBaseData untuk semua jenis data terkait laporan (jenis laporan, pengaturan perhitungan laporan, dll). TRBTempDatabase dibuat di TdmRBReport tetapi harus memiliki akses ke TdmReportBasedata. Jadi ini sekarang dilakukan dengan menggunakan konstruksi di atas:

constructor TRBTempDatabase.Create(aOwner: TComponent);
begin
  inherited Create(aOwner);

  FdmReportBaseData := TdmRBReport(FindOwnerClass(Owner, TdmRBReport)).dmReportBaseData;
end;{- .Create }

Perasaan saya adalah ini berarti bahwa TRBTempDatabase tahu banyak tentang pemiliknya, dan saya bertanya-tanya apakah ini semacam bau kode atau Anti-pola.

Apa pendapat anda tentang ini? Apakah ini bau kode? Jika demikian, apa cara yang lebih baik?

Bascy
sumber
1
Jika seharusnya tahu banyak tentang kelas lain itu akan disediakan cara yang lebih mudah untuk melakukannya.
Loren Pechtel

Jawaban:

13

Jenis ini terlihat seperti Pola Penentu Lokasi Layanan yang pertama kali dijelaskan oleh Martin Fowler (yang telah diidentifikasi sebagai anti-pola umum).

Injeksi Ketergantungan Berbasis Konstruksi lebih disukai daripada Service Locator karena mempromosikan visibilitas dari parameter yang diperlukan dan mempromosikan Pengujian Unit yang lebih sederhana.

Masalah dengan menggunakan Service Locator bukanlah bahwa Anda mengambil ketergantungan pada implementasi Service Locator tertentu (meskipun itu mungkin menjadi masalah juga), tetapi itu adalah anti-pola yang bonafide. Ini akan memberi konsumen API Anda pengalaman pengembang yang mengerikan, dan itu akan membuat hidup Anda sebagai pengembang pemeliharaan lebih buruk karena Anda perlu menggunakan kekuatan otak dalam jumlah yang cukup besar untuk memahami implikasi dari setiap perubahan yang Anda buat.

Kompiler dapat menawarkan konsumen dan produsen begitu banyak bantuan ketika Constructor Injection digunakan, tetapi tidak ada bantuan yang tersedia untuk API yang bergantung pada Service Locator.

Juga terutama melanggar Hukum Demeter

Law of Demeter (LoD) atau Principle of Least Knowledge adalah pedoman desain untuk mengembangkan perangkat lunak, khususnya program berorientasi objek. Dalam bentuk umumnya, LoD adalah kasus spesifik dari kopling longgar.

Hukum Demeter untuk fungsi mensyaratkan bahwa metode M suatu objek O hanya dapat memanggil metode dari jenis objek berikut ini:

  1. O sendiri
  2. Parameter M.
  3. benda apa pun yang dibuat / dipakai dalam M
  4. Objek komponen langsung O
  5. variabel global, dapat diakses oleh O, dalam lingkup M

Secara khusus, suatu objek harus menghindari metode pemanggilan objek anggota yang dikembalikan oleh metode lain. Untuk banyak bahasa berorientasi objek modern yang menggunakan titik sebagai pengidentifikasi bidang, hukum dapat dinyatakan hanya sebagai "gunakan hanya satu titik". Artinya, kode abMethod () melanggar hukum di mana a.Method () tidak. Sebagai contoh sederhana, ketika seseorang ingin berjalan seekor anjing, adalah bodoh untuk memerintahkan kaki anjing untuk berjalan langsung; alih-alih satu perintah pada anjing dan membiarkannya merawat kakinya sendiri.

Cara yang Lebih Baik

Secara efektif, cara yang lebih baik adalah menghapus panggilan locator layanan di dalam kelas, dan meneruskan pemilik yang benar sebagai parameter di dalam konstruktornya. Bahkan jika ini berarti bahwa Anda memiliki kelas layanan yang melakukan pencarian pemilik dan kemudian meneruskannya ke konstruktor kelas

constructor TRBTempDatabase.Create(aOwner: TComponent, ownerClass: IComponent);
begin
  inherited Create(aOwner);

  FdmReportBaseData := TdmRBReport(ownerClass).dmReportBaseData;
end;{- .Create }
Justin Shield
sumber
3
Jawaban yang bagus, dan alat bantu untuk siapa pun yang datang dengan analogi yang indah ini:As a simple example, when one wants to walk a dog, it would be folly to command the dog's legs to walk directly; instead one commands the dog and lets it take care of its own legs.
Andy Hunt
3

Salah satu kesulitan dengan memiliki objek anak mengetahui terlalu banyak tentang orangtua adalah bahwa Anda akhirnya menerapkan pola yang dapat (dan paling sering terjadi) menjadi terlalu erat, yang menciptakan sakit kepala ketergantungan besar dan sering kali kemudian menjadi sangat sulit untuk dimodifikasi & dirawat dengan aman. kemudian.

Tergantung pada seberapa dalam dua kelas Anda terhubung, kedengarannya agak seperti deskripsi Fowler tentang Fitur Envy atau Intimacy bau kode tidak terlihat jelas.

Tampaknya perlu memuat atau membaca kelas dengan data, dalam hal ini Anda dapat menggunakan sejumlah pola alternatif untuk memutus ketergantungan antara anak dan rantai orang tuanya, dan sepertinya Anda perlu mendelegasikan tugas mengakses kelas data Anda daripada membuat kelas pengakses data atau yang bertanggung jawab untuk melakukan semuanya sendiri.

S.Robins
sumber