Memisahkan kelas dari antarmuka pengguna


27

Apa praktik terbaik ketika datang ke kelas menulis yang mungkin harus tahu tentang antarmuka pengguna. Bukankah kelas yang tahu cara menggambar itu sendiri melanggar beberapa praktik terbaik karena itu tergantung pada apa antarmuka pengguna (konsol, GUI, dll)?

Dalam banyak buku pemrograman saya menemukan contoh "Shape" yang menunjukkan warisan. Bentuk kelas dasar memiliki metode draw () yang masing-masing bentuk seperti lingkaran dan menimpa persegi. Ini memungkinkan terjadinya polimorfisme. Tetapi bukankah metode draw () sangat tergantung pada apa antarmuka pengguna itu? Jika kita menulis kelas ini untuk mengatakan, Menangkan Formulir, maka kita tidak dapat menggunakannya kembali untuk aplikasi konsol atau aplikasi web. Apakah ini benar?

Alasan untuk pertanyaan ini adalah bahwa saya selalu terjebak dan menutup telepon tentang cara menggeneralisasi kelas sehingga mereka paling berguna. Ini sebenarnya bekerja melawan saya dan saya bertanya-tanya apakah saya "berusaha terlalu keras".


Mengapa Anda ingin memisahkan diri? Karena Anda dengar itu hal yang benar untuk dilakukan atau Anda punya alasan lain?
SoylentGray

2
Seluruh "kelas yang tahu cara menggambar itu sendiri" hanyalah contoh kuno yang mengerikan yang saya harap akan hilang. Terutama pada stack programmer game =)
Patrick Hughes

2
@Chad, aku tidak terlalu berpengalaman di luar sekolah. Saya sudah membaca buku dan saya benar-benar suka belajar dan membaca hal-hal baru tentang pola desain dan praktik terbaik. Jadi ya, bisa dibilang saya pernah mendengar bahwa decoupling itu baik tetapi juga masuk akal. Saya ingin menulis kode yang dapat saya gunakan untuk aplikasi WinForms desktop, misalnya, kemudian mengambil kode itu dan menggunakan kembali sebanyak mungkin untuk situs web atau bahkan aplikasi silverlight.
Pete

@Pete - Itu jawaban yang bagus.
SoylentGray

2
@ Patrick: untuk bersikap adil, jika Anda menulis Shapekelas, maka Anda mungkin menulis tumpukan grafik itu sendiri, bukan menulis klien ke tumpukan grafik.
Ken Bloom

Jawaban:


13

Apa praktik terbaik ketika datang ke kelas menulis yang mungkin harus tahu tentang antarmuka pengguna. Bukankah kelas yang tahu cara menggambar itu sendiri melanggar beberapa praktik terbaik karena itu tergantung pada apa antarmuka pengguna (konsol, GUI, dll)?

Itu tergantung pada kelas dan kasus penggunaan. Unsur visual yang mengetahui cara menggambar itu sendiri belum tentu merupakan pelanggaran prinsip tanggung jawab tunggal.

Dalam banyak buku pemrograman saya menemukan contoh "Shape" yang menunjukkan warisan. Bentuk kelas dasar memiliki metode draw () yang masing-masing bentuk seperti lingkaran dan menimpa persegi. Ini memungkinkan terjadinya polimorfisme. Tetapi bukankah metode draw () sangat tergantung pada apa antarmuka pengguna itu?

Sekali lagi, belum tentu. Jika Anda bisa membuat antarmuka (drawPoint, drawLine, atur Warna, dll.), Anda dapat melewati konteks apa pun untuk menggambar sesuatu ke sesuatu ke bentuk, misalnya dalam konstruktor bentuk itu. Ini akan memungkinkan bentuk untuk menggambar diri mereka sendiri di konsol atau kanvas yang diberikan.

Jika kita menulis kelas ini untuk mengatakan, Menangkan Formulir, maka kita tidak dapat menggunakannya kembali untuk aplikasi konsol atau aplikasi web. Apakah ini benar?

Ya benar. Jika Anda menulis UserControl (bukan kelas pada umumnya) untuk Formulir Windows, maka Anda tidak akan dapat menggunakannya dengan konsol. Tapi itu bukan masalah. Mengapa Anda mengharapkan UserControl untuk Formulir Windows berfungsi dengan segala jenis presentasi? UserControl harus melakukan satu hal dan melakukannya dengan baik. Ini terikat pada bentuk presentasi tertentu menurut definisi. Pada akhirnya, pengguna membutuhkan sesuatu yang konkret dan bukan abstraksi. Ini mungkin hanya sebagian benar untuk kerangka kerja, tetapi untuk aplikasi pengguna akhir, itu.

Namun, logika di baliknya harus dipisahkan, sehingga Anda dapat menggunakannya lagi dengan teknologi presentasi lainnya. Perkenalkan antarmuka jika perlu, untuk mempertahankan ortogonalitas untuk aplikasi Anda. Aturan umumnya adalah: Hal-hal konkret harus dapat ditukar dengan hal-hal konkret lainnya.

Alasan untuk pertanyaan ini adalah bahwa saya selalu terjebak dan menutup telepon tentang cara menggeneralisasi kelas sehingga mereka paling berguna. Ini sebenarnya bekerja melawan saya dan saya bertanya-tanya apakah saya "berusaha terlalu keras".

Anda tahu, programmer ekstrim menyukai sikap YAGNI mereka . Jangan mencoba menulis semuanya secara umum dan jangan berusaha terlalu keras untuk membuat semuanya menjadi tujuan umum. Ini disebut rekayasa ulang dan pada akhirnya akan mengarah pada kode yang benar-benar berbelit-belit. Berikan masing-masing komponen tugas yang tepat dan pastikan komponen itu bekerja dengan baik. Masukkan abstraksi jika perlu, di mana Anda mengharapkan hal-hal berubah (misalnya antarmuka untuk menggambar konteks, seperti yang dinyatakan di atas).

Secara umum, ketika menulis aplikasi bisnis, Anda harus selalu mencoba untuk memisahkan hal-hal. MVC dan MVVM sangat bagus untuk memisahkan logika dari presentasi, sehingga Anda dapat menggunakannya kembali untuk presentasi web atau aplikasi konsol. Perlu diingat bahwa pada akhirnya, beberapa hal harus konkret. Pengguna Anda tidak dapat bekerja dengan abstraksi, mereka membutuhkan sesuatu yang konkret. Abstraksi hanya membantu Anda, sang programmer, agar kode dapat diperluas dan dipelihara. Anda perlu memikirkan di mana Anda membutuhkan kode Anda agar fleksibel. Akhirnya semua abstraksi harus melahirkan sesuatu yang konkret.

Sunting: Jika Anda ingin membaca lebih lanjut tentang arsitektur dan teknik desain yang dapat memberikan praktik terbaik, saya sarankan Anda membaca jawaban @Catchops dan membaca tentang praktik SOLID di wikipedia.

Sebagai permulaan, saya selalu merekomendasikan buku berikut: Head First Design Patterns . Ini akan membantu Anda memahami teknik abstraksi / praktik desain OOP, lebih dari buku GoF (yang sangat bagus, hanya saja tidak cocok untuk pemula).


1
Jawaban yang bagus, tetapi programmer yang ekstrem tidak 'melakukan abstraksi di mana kita mengharapkan sesuatu berubah'. Kami membuat abstraksi di mana hal - hal berubah, untuk KERING kode.
kevin cline

1
@kevin cline itu luar biasa kecuali jika Anda mendesain perpustakaan yang tersedia untuk umum dengan API yang perlu menyesuaikan dengan perilaku dan antarmuka sebelumnya.
Magnus Wolffelt

@ Magnus - ya, mendesain perpustakaan dalam beberapa bahasa, merencanakan kompatibilitas mundur biner, rumit. Seseorang dipaksa untuk menulis segala macam kode yang saat ini tidak dibutuhkan untuk memungkinkan perpanjangan di masa depan. Ini mungkin masuk akal untuk bahasa yang dikompilasi dengan logam. Ini konyol untuk bahasa yang dikompilasi ke mesin virtual.
kevin cline

19

Anda pasti benar. Dan tidak, Anda "berusaha dengan baik" :)

Baca tentang prinsip tanggung jawab tunggal

Pekerjaan batin Anda di kelas dan cara informasi ini disajikan kepada pengguna adalah dua tanggung jawab.

Jangan takut untuk memisahkan kelas. Jarang masalahnya adalah terlalu banyak abstraksi dan decoupling :)

Dua pola yang sangat relevan adalah Model-view-controller untuk aplikasi web dan Model View ViewModel untuk Silverlight / WPF.


1
+1 Anda bahkan dapat menggunakan MVC untuk aplikasi bukan-web, paling tidak itu membantu Anda berpikir dalam istilah yang menjaga tanggung jawab tetap jelas.
Patrick Hughes

MVVM adalah silimar ke MVC. MVC sebagian besar untuk aplikasi tanpa negara seperti aplikasi web.
Boris Yankov

3
-1 Menurut pengalaman saya, salah satu masalah yang paling umum adalah generalisasi prematur dan rekayasa berlebihan secara umum.
dietbuddha

3
Pertama-tama Anda harus tahu cara merekayasa sesuatu untuk merekayasa secara berlebihan. Dalam pengalaman saya, perangkat lunak 'insinyur bawah' orang jauh lebih sering.
Boris Yankov

Sementara saya menghargai upaya untuk meningkatkan desain perangkat lunak, mengganti panggilan di antarmuka, untuk panggilan di kelas, tidak memisahkan apa pun secara semantik. Pertimbangkan apa yang terjadi ketika menggunakan bahasa yang diketik secara dinamis. Ada terlalu banyak penekanan pada decoupling superfisial (sintaksis), dan sedikit pada decoupling sejati, dalam saran yang diberikan di bagian programmer dari pertukaran stack.
Frank Hileman

7

Saya sering menggunakan MVVM dan menurut pendapat saya, kelas objek bisnis seharusnya tidak perlu tahu apa-apa tentang antarmuka pengguna. Tentu mereka mungkin perlu mengetahui SelectedItem, atau IsChecked, atau IsVisible, dll, tetapi nilai-nilai itu tidak perlu mengikat ke UI tertentu dan dapat menjadi properti generik di kelas.

Jika Anda perlu melakukan sesuatu pada antarmuka di belakang kode, seperti mengatur Fokus, menjalankan Animasi, menangani Hot Keys, dll. Maka kode tersebut harus menjadi bagian dari kode-belakang UI, bukan kelas logika bisnis Anda.

Jadi saya akan mengatakan jangan berhenti mencoba memisahkan UI dan kelas Anda. Semakin terpisah mereka, semakin mudah untuk mempertahankan dan menguji.


5

Ada sejumlah pola desain yang sudah terbukti dan telah dikembangkan selama bertahun-tahun untuk menjawab apa yang Anda bicarakan. Jawaban lain untuk pertanyaan Anda merujuk pada Prinsip Satu Tanggung Jawab - yang benar-benar valid - dan apa yang tampaknya mendorong pertanyaan Anda. Prinsip itu hanya menyatakan bahwa suatu kelas perlu melakukan satu hal BAIK. Dengan kata lain meningkatkan Kohesi dan menurunkan Kopling yang merupakan tujuan dari desain berorientasi objek yang baik - apakah kelas melakukan satu hal dengan baik, dan tidak memiliki banyak ketergantungan pada yang lain.

Nah ... Anda benar dalam mengamati bahwa jika Anda ingin menggambar lingkaran pada iPhone, itu akan berbeda dari menggambar satu pada PC yang menjalankan windows. Anda HARUS memiliki (dalam hal ini) kelas konkret yang menggambar satu sumur di iPhone, dan lainnya yang menarik satu sumur di PC. Di sinilah dasar OO dasar warisan yang semua contoh bentuk itu rusak. Anda tidak bisa melakukannya dengan warisan saja.

Di situlah antarmuka masuk - seperti yang dinyatakan oleh buku Gang of Four (HARUS BACA) - Selalu mendukung implementasi daripada warisan. Dengan kata lain, gunakan antarmuka untuk menyatukan arsitektur yang dapat melakukan berbagai fungsi dalam banyak cara tanpa bergantung pada dependensi kode keras.

Saya telah melihat referensi pada prinsip-prinsip SOLID . Itu bagus. 'S' adalah prinsip tanggung jawab tunggal. NAMUN, 'D' adalah singkatan dari Dependency Inversion. Pola Inversion of Control (Injeksi Ketergantungan) dapat digunakan di sini. Ini sangat kuat dan dapat digunakan untuk menjawab pertanyaan tentang bagaimana merancang sistem yang dapat menggambar lingkaran untuk iPhone serta satu untuk PC.

Dimungkinkan untuk membuat arsitektur yang berisi aturan bisnis umum dan akses data, tetapi memiliki berbagai implementasi antarmuka pengguna menggunakan konstruk ini. Namun, sangat membantu untuk benar-benar berada di tim yang mengimplementasikannya dan melihatnya beraksi untuk benar-benar memahaminya.

Ini hanyalah jawaban tingkat tinggi yang cepat untuk sebuah pertanyaan yang pantas mendapatkan jawaban yang lebih terperinci. Saya mendorong Anda untuk melihat lebih jauh ke dalam pola-pola ini. Beberapa implementasi yang lebih nyata dari patters ini dapat ditemukan sebagai nama-nama terkenal dari MVC dan MVVM.

Semoga berhasil!


Saya suka ketika seseorang merendahkan sesuatu tanpa memberikan komentar mengapa (sarkasme, tentu saja). Prinsip-prinsip yang saya nyatakan adalah benar - akankah orang yang kecewa silakan berdiri dan mengatakan alasannya.
Catchops

2

Apa praktik terbaik ketika datang ke kelas menulis yang mungkin harus tahu tentang antarmuka pengguna.

Bukankah kelas yang tahu cara menggambar itu sendiri melanggar beberapa praktik terbaik karena itu tergantung pada apa antarmuka pengguna (konsol, GUI, dll)?

Dalam hal ini Anda masih dapat menggunakan MVC / MVVM dan menyuntikkan berbagai implementasi UI menggunakan antarmuka umum:

public interface IAgnosticChartDrawing
{
   public void Draw(ChartProperties chartProperties);
   event EventHandler ChartPanned;
}

public class GuiChartDrawer : UserControl, IAgnosticChartDrawing
{
    public void Draw(ChartProperties chartProperties)
    {
        //GDI, GTK or something else...
    }

    //Implement event based on mouse actions
}

public class ConsoleChartDrawer : IAgnosticChartDrawing
{
    public void Draw(ChartProperties chartProperties)
    {
        //'Draw' using characters and symbols...
    }

    //Implement event based on keyboard actions
}

IAgnosticChartDrawing guiView = new GuiChartDrawer();
IAgnosticChartDrawing conView = new ConsoleChartDrawer();

Model model = new FinancialModel();

SampleController controllerGUI = new SampleController(model, guiView);
SampleController controllerConsole = new SampleController(model, conView);

Dengan cara ini Anda akan dapat menggunakan kembali Kontroler dan Model logika Anda sambil dapat menambahkan GUI jenis baru.


2

Ada beberapa pola untuk melakukannya: MVP, MVC, MVVM, dll ...

Artikel bagus dari Martin Fowler (nama besar) untuk dibaca adalah Arsitektur GUI: http://www.martinfowler.com/eaaDev/uiArchs.html

MVP belum disebutkan tetapi pasti layak untuk dikutip: lihatlah.

Ini adalah pola yang disarankan oleh pengembang Google Web Toolkit untuk digunakan, ini sangat rapi.

Anda dapat menemukan kode nyata, contoh nyata, dan alasan mengapa pendekatan ini bermanfaat di sini:

http://code.google.com/webtoolkit/articles/mvp-architecture.html

http://code.google.com/webtoolkit/articles/mvp-architecture-2.html

Salah satu keuntungan mengikuti ini atau pendekatan serupa yang belum cukup ditekankan di sini adalah testabilitas! Dalam banyak kasus saya akan mengatakan itu adalah keuntungan utama!


1
+1 untuk tautan. Saya membaca artikel serupa di MSDN tentang MVVM dan artikel-artikel google itu jauh lebih baik meskipun dengan pola yang sedikit berbeda.
Pete

1

Ini adalah salah satu tempat di mana OOP gagal melakukan pekerjaan dengan baik di abstraksi. Polimorfisme OOP menggunakan pengiriman dinamis atas satu variabel ('ini'). Jika polimorfisme telah di-root pada Shape maka Anda tidak dapat mengirim polimorfik sekutu pada renderer (konsol, GUI, dll).

Pertimbangkan sistem pemrograman yang dapat mengirimkan dua atau lebih variabel:

poly_draw(Shape s, Renderer r)

dan juga anggap sistem dapat memberi Anda cara untuk mengekspresikan poly_draw untuk berbagai kombinasi tipe Shape dan tipe Renderer. Maka akan mudah untuk membuat klasifikasi bentuk dan penyaji, bukan? Pemeriksa tipe entah bagaimana akan membantu Anda mencari tahu apakah ada kombinasi bentuk dan renderer yang mungkin Anda lewatkan penerapannya.

Sebagian besar bahasa OOP tidak mendukung apa pun seperti di atas (beberapa melakukannya, tetapi mereka tidak umum). Saya sarankan Anda melihat pola Pengunjung untuk solusinya.


1

... bukankah metode draw () sangat tergantung pada apa antarmuka pengguna itu? Jika kita menulis kelas ini untuk mengatakan, Menangkan Formulir, maka kita tidak dapat menggunakannya kembali untuk aplikasi konsol atau aplikasi web. Apakah ini benar?

Di atas terdengar benar bagi saya. Menurut pemahaman saya, bisa dikatakan itu berarti kopling yang relatif ketat antara Controller dan View dalam hal pola desain MVC. Ini juga berarti bahwa untuk beralih antara desktop-konsol-webapp kita harus beralih baik Controller dan View sebagai pasangan - hanya model tetap tidak berubah.

... Saya menemukan diri saya selalu terjebak dan menutup telepon tentang cara menggeneralisasi kelas sehingga mereka paling berguna.

Nah pendapat saya saat ini di atas adalah bahwa kopling View-Controller yang kita bicarakan ini OK dan bahkan lebih, itu agak trendi dalam desain modern.

Padahal, satu atau dua tahun yang lalu saya juga merasa tidak aman tentang itu. Saya berubah pikiran setelah mempelajari diskusi di forum Sun mengenai pola dan desain OO.

Jika Anda tertarik, coba sendiri forum ini - forum ini telah bermigrasi ke Oracle sekarang ( tautan ). Jika Anda sampai di sana, coba ping pria Saish - saat itu, penjelasannya tentang masalah rumit ini ternyata paling membantu saya. Saya tidak tahu apakah dia masih berpartisipasi - saya sendiri belum pernah ke sana cukup lama


1

Tetapi bukankah metode draw () sangat tergantung pada apa antarmuka pengguna itu?

Dari pandangan pragmatis, beberapa kode di sistem Anda perlu tahu cara menggambar sesuatu seperti Rectanglejika itu persyaratan pengguna-akhir. Dan itu akan memanas pada titik tertentu untuk melakukan hal-hal yang sangat rendah seperti rasterisasi piksel atau menampilkan sesuatu di konsol.

Pertanyaan saya dari sudut pandang penggandaan adalah siapa / apa yang harus bergantung pada jenis informasi ini, dan sampai pada tingkat detail apa (seberapa abstrak, misalnya)?

Mengabstraksi Gambar / Kemampuan Rendering

Karena jika kode gambar tingkat tinggi hanya bergantung pada sesuatu yang sangat abstrak, abstraksi itu mungkin dapat bekerja (melalui substitusi implementasi konkret) pada semua platform yang Anda targetkan. Sebagai contoh yang dibuat-buat, beberapa IDrawerantarmuka yang sangat abstrak mungkin dapat diimplementasikan di kedua konsol dan API GUI untuk melakukan hal-hal seperti bentuk plot (implementasi konsol mungkin memperlakukan konsol seperti beberapa "gambar" 80xN dengan seni ASCII). Tentu saja itu adalah contoh yang dibuat karena biasanya bukan itu yang ingin Anda lakukan adalah memperlakukan keluaran konsol seperti penyangga gambar / bingkai; biasanya sebagian besar pengguna akhir membutuhkan panggilan untuk lebih banyak interaksi berbasis teks di konsol.

Pertimbangan lain adalah seberapa mudahkah mendesain abstraksi yang stabil? Karena mungkin mudah jika semua yang Anda targetkan adalah API GUI modern untuk mengabstraksi kemampuan menggambar bentuk dasar seperti merencanakan garis, persegi panjang, jalur, teks, hal-hal semacam ini (hanya rasterisasi 2D sederhana dari kumpulan primitif terbatas) , dengan satu antarmuka abstrak yang dapat dengan mudah diimplementasikan untuk mereka semua melalui berbagai subtipe dengan sedikit biaya. Jika Anda dapat mendesain abstraksi seperti itu secara efektif dan mengimplementasikannya pada semua platform target, maka saya akan mengatakan itu adalah kejahatan yang jauh lebih kecil, jika bahkan kejahatan sama sekali, untuk bentuk atau kontrol GUI atau apa pun untuk mengetahui cara menggambar dirinya sendiri menggunakan abstraksi.

Tetapi katakan Anda mencoba untuk mengabstraksikan detail berdarah yang bervariasi antara Playstation Portable, iPhone, XBox One, dan PC gaming yang tangguh sementara kebutuhan Anda adalah memanfaatkan teknik rendering / peneduhan 3D real-time paling mutakhir pada masing-masing . Dalam hal ini mencoba untuk membuat satu antarmuka abstrak untuk mengabstraksi rincian render ketika kemampuan perangkat keras dan API yang bervariasi sangat liar hampir pasti akan menghasilkan waktu yang sangat besar dalam mendesain dan mendesain ulang, kemungkinan besar perubahan desain berulang dengan tak terduga. penemuan, dan juga solusi denominator umum terendah yang gagal mengeksploitasi keunikan dan kekuatan penuh dari perangkat keras yang mendasarinya.

Membuat Aliran Ketergantungan Menuju Desain Yang Stabil, "Mudah"

Di bidang saya, saya berada dalam skenario terakhir itu. Kami menargetkan banyak perangkat keras yang berbeda dengan kemampuan dan API yang mendasari sangat berbeda, dan untuk mencoba menghasilkan satu abstraksi rendering / menggambar untuk memerintah mereka semua adalah tanpa batas (kita mungkin menjadi terkenal di dunia hanya melakukan itu secara efektif karena itu akan menjadi permainan) changer di industri). Jadi, hal terakhir yang saya inginkan dalam kasus saya adalah seperti analog Shapeatau Modelatau Particle Emitteryang tahu cara menggambar itu sendiri, bahkan jika itu menyatakan bahwa menggambar dengan cara tingkat tertinggi dan paling abstrak mungkin ...

... karena abstraksi-abstraksi itu terlalu sulit untuk dirancang dengan benar, dan ketika sebuah desain sulit untuk mendapatkan yang benar, dan semuanya tergantung padanya, itu adalah resep untuk perubahan desain pusat yang paling mahal yang mengacak-acak dan menghancurkan semuanya tergantung padanya. Jadi hal terakhir yang Anda inginkan adalah ketergantungan pada sistem Anda mengalir ke desain abstrak yang terlalu sulit untuk diperbaiki (terlalu sulit untuk distabilkan tanpa perubahan yang mengganggu).

Tergantung Sulit pada Mudah, Tidak Mudah Tergantung pada Sulit

Jadi yang kami lakukan adalah membuat ketergantungan mengalir ke hal-hal yang mudah dirancang. Jauh lebih mudah untuk mendesain "Model" abstrak yang hanya berfokus pada penyimpanan hal-hal seperti poligon dan material dan mendapatkan desain yang benar daripada mendesain "Renderer" abstrak yang dapat secara efektif diimplementasikan (melalui subtipe beton yang dapat diganti-ganti) untuk melayani gambar meminta secara seragam untuk perangkat keras yang berbeda seperti PSP dari PC.

masukkan deskripsi gambar di sini

Jadi kami membalikkan ketergantungan dari hal-hal yang sulit untuk dirancang. Alih-alih membuat model abstrak tahu cara menggambar diri mereka sendiri ke desain renderer abstrak yang mereka semua andalkan (dan merusak implementasinya jika desain itu berubah), kami malah memiliki renderer abstrak yang tahu cara menggambar setiap objek abstrak di adegan kami ( model, penghasil partikel, dll), dan dengan demikian kita dapat menerapkan subtipe renderer OpenGL untuk PC seperti RendererGl, yang lain untuk PSP seperti RendererPsp, yang lain untuk ponsel, dll. Dalam hal ini dependensi mengalir ke desain yang stabil, mudah untuk mendapatkan yang benar, dari renderer ke berbagai jenis entitas (model, partikel, tekstur, dll) dalam adegan kami, bukan sebaliknya.

masukkan deskripsi gambar di sini

  • Saya menggunakan "stabilitas / ketidakstabilan" dalam arti yang sedikit berbeda dari metrik kopling aferen / eferen Paman Bob yang mengukur lebih banyak kesulitan perubahan sejauh yang saya bisa mengerti. Saya berbicara lebih banyak tentang "probabilitas membutuhkan perubahan", meskipun metrik stabilitasnya berguna di sana. Ketika "probabilitas perubahan" sebanding dengan "kemudahan perubahan" (mis: hal-hal yang paling mungkin memerlukan perubahan memiliki ketidakstabilan dan kopling aferen tertinggi dari metrik Paman Bob), maka segala kemungkinan perubahan itu murah dan tidak mengganggu untuk dilakukan. , hanya membutuhkan penggantian implementasi tanpa menyentuh desain pusat.

Jika Anda menemukan diri Anda mencoba untuk mengabstraksi sesuatu di tingkat pusat basis kode Anda dan itu terlalu sulit untuk dirancang, alih-alih dengan keras kepala memukul dinding dan terus-menerus membuat perubahan yang mengganggu setiap bulan / tahun yang membutuhkan memperbarui 8.000 file sumber karena itu melanggar semua yang tergantung padanya, saran nomor satu saya adalah mempertimbangkan membalikkan dependensi. Lihat apakah Anda dapat menulis kode sedemikian rupa sehingga hal yang sangat sulit untuk dirancang tergantung pada segala sesuatu yang lebih mudah untuk dirancang, tidak memiliki hal-hal yang lebih mudah untuk dirancang tergantung pada hal yang sangat sulit untuk dirancang. Perhatikan bahwa saya berbicara tentang desain (khususnya desain antarmuka) dan bukan implementasi: kadang-kadang hal-hal mudah dirancang dan sulit diimplementasikan, dan terkadang hal-hal sulit untuk dirancang tetapi mudah diimplementasikan. Ketergantungan mengalir ke arah desain, jadi fokusnya seharusnya hanya pada seberapa sulit sesuatu untuk merancang di sini untuk menentukan arah di mana dependensi mengalir.

Prinsip Tanggung Jawab Tunggal

Bagi saya SRP tidak begitu menarik di sini biasanya (meskipun tergantung pada konteksnya). Maksud saya ada tindakan menyeimbangkan tali ketat dalam mendesain hal-hal yang jelas dalam tujuan dan dapat dipelihara tetapi Shapeobjek Anda mungkin harus memaparkan informasi yang lebih rinci jika mereka tidak tahu cara menggambar diri mereka sendiri, misalnya, dan mungkin tidak ada banyak hal yang bermakna untuk lakukan dengan bentuk dalam konteks penggunaan tertentu daripada membangunnya dan menggambarnya. Ada pertukaran dengan hampir semua hal, dan itu tidak terkait dengan SRP yang dapat membuat hal-hal sadar bagaimana menggambar diri mereka mampu menjadi mimpi buruk pemeliharaan dalam pengalaman saya dalam konteks tertentu.

Ini lebih terkait dengan kopling dan arah aliran dependensi dalam sistem Anda. Jika Anda mencoba untuk mem-port antarmuka rendering abstrak yang semuanya bergantung (karena mereka menggunakannya untuk menggambar sendiri) ke API / perangkat keras target baru dan menyadari bahwa Anda harus mengubah desainnya untuk membuatnya bekerja secara efektif di sana, maka itu adalah perubahan yang sangat mahal untuk dilakukan yang membutuhkan penggantian implementasi segala sesuatu di sistem Anda yang tahu cara menggambar sendiri. Dan itulah masalah perawatan paling praktis yang saya temui dengan hal-hal yang disadari tentang cara menggambar diri mereka sendiri jika itu berarti muatan perahu yang mengalir ke arah abstraksi yang terlalu sulit untuk dirancang dengan benar di muka.

Kebanggaan Pengembang

Saya menyebutkan satu poin ini karena, dalam pengalaman saya, ini sering merupakan hambatan terbesar untuk mengalirkan arah ketergantungan kepada hal-hal yang lebih mudah untuk dirancang. Sangat mudah bagi pengembang untuk menjadi sedikit ambisius di sini dan berkata, "Saya akan merancang abstraksi rendering lintas platform untuk mengatur semuanya, saya akan menyelesaikan apa yang menghabiskan waktu berbulan-bulan bagi pengembang lain dalam porting, dan saya akan mendapatkan itu benar dan itu akan bekerja seperti sulap pada setiap platform yang kami dukung dan gunakan teknik rendering canggih pada setiap platform; Saya sudah membayangkannya di kepala saya. "Dalam hal ini mereka menolak solusi praktis yaitu untuk menghindari melakukan itu dan hanya membalik arah dependensi dan menerjemahkan apa yang mungkin sangat mahal dan berulang perubahan desain pusat untuk perubahan hanya murah dan lokal untuk implementasi. Perlu ada semacam naluri "bendera putih" di pengembang untuk menyerah ketika ada sesuatu yang terlalu sulit untuk dirancang ke tingkat abstrak dan mempertimbangkan kembali seluruh strategi mereka, kalau tidak mereka akan menghadapi banyak kesedihan dan rasa sakit. Saya akan menyarankan untuk mentransfer ambisi dan semangat juang seperti itu ke implementasi canggih dari hal yang lebih mudah untuk dirancang daripada mengambil ambisi menaklukkan dunia ke tingkat desain antarmuka.


1
Saya sepertinya tidak dapat memahami ide "membalikkan ketergantungan dari hal-hal yang sulit untuk dirancang", apakah Anda berbicara tentang pewarisan saja? Menggunakan contoh PSP / OpenGL, maksud Anda alih-alih membuat OpenGLBillboard, Anda akan membuat OpenGLRendereryang tahu cara menggambar jenis apa pun IBillBoard? Tetapi akankah hal itu dilakukan dengan mendelegasikan logika IBillBoard, atau akankah ia memiliki saklar atau IBillBoardtipe besar dengan persyaratan? Itulah yang sulit saya pahami, karena itu sepertinya tidak dapat dipertahankan sama sekali!
Steve Chamaillard

@SteveChamaillard Perbedaannya adalah, katakanlah, PSP (perangkat keras terbatas) harus menangani volume primitif menggunakan sekolah tua screendoor transparansi dan urutan berbeda dalam memberikan evaluasi: digitalrune.github.io/DigitalRune-Documentation/media/… . Ketika Anda memiliki satu pusat RendererPspyang mengetahui abstraksi tingkat tinggi dari adegan permainan Anda, maka ia dapat melakukan semua keajaiban dan membalikkan yang diperlukan untuk membuat hal-hal seperti itu dengan cara yang terlihat meyakinkan di PSP ....
Dragon Energy

Sedangkan jika Anda memiliki volume primitif seperti yang meminta untuk membuat sendiri, baik operasi mereka sangat tinggi sehingga pada dasarnya mereka menentukan diri mereka untuk dirender (yang tidak ada bedanya kecuali bundaran bundaran dan penggabungan lebih lanjut), atau abstraksi penyaji tidak mampu benar-benar melakukan hal-hal dengan cara yang paling efektif yang mungkin dilakukan pada PSP (setidaknya tanpa melakukan backflips, yang tidak perlu dilakukan jika dependensinya terbalik).
Dragon Energy

1
Ok saya pikir saya mengerti sekarang. Pada dasarnya Anda mengatakan bahwa masalah seperti itu (yaitu perangkat keras) sangat tinggi sehingga membuat objek tingkat rendah seperti BillBoardbergantung pada hal itu akan sangat sulit dilakukan? Sedangkan IRenderertingkat tinggi sudah dan bisa bergantung pada masalah ini dengan masalah jauh lebih sedikit?
Steve Chamaillard

1
Dengan keprihatinan rendering mutakhir pada platform yang berbeda, kemampuan perangkat keras yang berbeda, terlalu sulit untuk merancang sesuatu di mana saya bos dan katakan apa yang harus dilakukan. Jauh lebih mudah bagi saya untuk mengatakan, "Hei, saya keruh / berkabut dengan partikel berair keabu-abuan seperti ini, dan cobalah untuk membuat saya terlihat baik, jangan tangkap leher saya yang belum saya cukur belakangan ini", dan biarkan penyaji mengetahui cara membuat saya dengan cara yang seindah dan seketika mungkin mengingat keterbatasan yang dikerjakannya. Setiap upaya untuk mengatakan apa yang harus dilakukan hampir pasti akan menghasilkan jalan yang kontraproduktif.
Dragon Energy
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.