Apakah itu "bau pola" untuk menempatkan getter seperti "FullName" atau "FormattedPhoneNumber" dalam model Anda?

13

Saya sedang mengerjakan aplikasi ASP.NET MVC, dan saya sudah terbiasa membiasakan apa yang kelihatannya membantu dan nyaman digunakan dalam kelas model / entitas saya.

Sebagai contoh:

public class Member
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }

    public string FullName
    {
        get { return FirstName + " " + LastName; }
    }

    public string FormattedPhoneNumber
    {
        get { return "(" + PhoneNumber.Substring(0, 3) + ") " + PhoneNumber.Substring(3, 3) + "-" + PhoneNumber.Substring(6); }
    }
}

Saya bertanya-tanya orang-orang memikirkan FullNamedan mendapatkan FormattedPhoneNumber.

Mereka membuatnya sangat mudah untuk membuat format data standar di seluruh aplikasi, dan mereka tampaknya menyimpan banyak kode berulang, tetapi dapat dipastikan bahwa format data adalah sesuatu yang harus ditangani dalam pemetaan dari model ke model-tampilan.

Sebenarnya, saya awalnya menerapkan format data ini di lapisan layanan saya di mana saya melakukan pemetaan, tetapi itu menjadi beban untuk terus-menerus harus menulis formatters kemudian menerapkannya di banyak tempat berbeda. Misalnya, saya menggunakan "Nama Lengkap" di sebagian besar tampilan, dan harus mengetikkan sesuatu seperti di model.FullName = MappingUtilities.GetFullName(entity.FirstName, entity.LastName);semua tempat tampak jauh lebih elegan daripada hanya mengetik model.FullName = entity.FullName(atau, jika Anda menggunakan sesuatu seperti AutoMapper, berpotensi tidak mengetik apa pun).

Jadi, di mana Anda menggambar garis ketika datang ke pemformatan data. Apakah "boleh" melakukan pemformatan data dalam model Anda atau apakah itu "pola bau"?

Catatan: Saya jelas tidak memiliki html dalam model saya. Saya menggunakan pembantu html untuk itu. Saya benar-benar berbicara tentang memformat atau menggabungkan data (dan terutama data yang sering digunakan).

penjahat
sumber
1
Melakukan ini bisa nyaman. Tetapi harap dan doakan agar Anda tidak perlu menginternasionalkan kode itu.
btilly
@ btilly, poin bagus, tapi saya sekitar 99,99% yakin bahwa saya tidak akan.
devuxer
Khusus untuk FullName dan PhoneNumber, pasti. Apakah pertanyaan khusus tentang mereka karena mereka memiliki format yang tidak konsisten dalam budaya yang berbeda, atau apakah @DanM hanya mengambil contoh yang tidak terinternasionalisasi dengan baik untuk pertanyaan yang lebih umum?
Greg Jackson
@ Greg Jackson, pasti tangga. Seperti yang ditunjukkan ammoQ, PhoneNumbermungkin termasuk dalam kelasnya sendiri (yang sekarang telah saya implementasikan). Tetapi FullNamesebenarnya adalah hal yang memotivasi saya untuk menulis pertanyaan. Tapi saya tertarik untuk mencari tahu apakah, secara umum, masuk akal untuk meletakkan pemformatan data / menyisir, dll dalam model untuk hal-hal yang akan berlaku di seluruh aplikasi. Dari jawaban di bawah, sepertinya ini bukan anti-pola, tetapi keputusan harus dibuat dengan hati-hati.
devuxer
Ingatlah bahwa pemformatan khusus untuk nama lengkap ini mungkin juga tidak dapat diterapkan secara internasional. Di Asia Timur, misalnya, urutan nama terbalik dari apa yang ada di dunia Barat. Apakah Anda benar-benar perlu menangani ini secara eksplisit? Mungkin tidak, tetapi perlu diingat bahwa ada banyak hal rumit yang akan Anda temui ketika memformat data.
Greg Jackson

Jawaban:

9

Dalam contoh Anda, saya menyukai FullNamepengambil (untuk semua alasan yang Anda berikan) tetapi saya tidak suka pengambil FormattedPhoneNumber. Alasannya adalah: itu mungkin tidak mudah (setelah Anda memiliki nomor telepon internasional, dll.) Dan jika Anda menempatkan logika untuk memformat nomor telepon dalam suatu metode Member, kemungkinan Anda perlu melakukan refactor (atau salin-tempelkan caugh ) begitu Anda perlu nomor telepon yang diformat untuk Institution, Vendordll juga.

EDIT: IMO akan lebih baik untuk memiliki PhoneNumberkelas dengan Formattedpengambil.

pengguna281377
sumber
+1 dan terima kasih. Tetapi bagaimana jika saya benar-benar memasukkan kode pemformatan nomor telepon saya dalam metode ekstensi? Maka model apa pun bisa menggunakannya, dan tidak akan ada refactoring atau copy / paste. Solusi ini akan tetap jauh lebih sedikit berulang daripada menerapkan formatter ke setiap nomor telepon yang muncul di setiap tampilan.
devuxer
3
Menggunakan metode ekstensi untuk itu akan menjadi cara cepat untuk antipattern "dekomposisi fungsional". Dengan menggunakan metode ekstensi (untuk Stringkelas, saya kira), Anda "mengajar" Stringkelas bagaimana memformat nomor telepon. Apakah benar-benar tanggung jawab Stringkelas untuk mengetahui nomor telepon? Saya kira tidak. Digunakan seperti itu, metode ekstensi adalah gula sintaksis untuk membiarkan sesuatu yang jelas-jelas tidak berorientasi objek terlihat seperti itu.
user281377
1
Oke, lupakan saya katakan metode ekstensi. Berpura-puralah saya katakan metode utilitas atau kelas formatter. Saya hanya mengatakan bahwa refactoring / copy paste tidak perlu, terlepas dari apakah saya memiliki pengambil model atau melakukan format di tempat lain.
devuxer
1
Dan saya suka ide PhoneNumberkelas. Saya sudah berencana melakukan itu karena saya juga punya PhoneTypeproperti.
devuxer
Saya tidak suka gagasan memiliki PhoneNumberkelas instan karena datanya asli string. Sebaliknya, itu harus berupa kelas statis dengan metode seperti public static string Format(string phoneNumber, PhoneNumberStyle style).
Mr Anderson
5

Hal-hal yang perlu Anda pertimbangkan ketika menulis kode: Apakah itu benar? Apakah bisa dibaca? Apakah efisien? Apakah bisa dirawat? Saya berpendapat, seperti yang disebutkan @btilly, bahwa itu tidak dapat dikelola karena pemformatan khusus budaya, tetapi pertanyaannya tampaknya lebih umum daripada itu.

Menggunakan pengakses seperti ini membuat kode Anda lebih mudah dibaca, dan, tergantung bagaimana Anda menggunakannya, mungkin membuat bagian lain dari kode Anda jauh lebih bersih. Menurut saya, itu tidak berbau sama sekali. Itu akan mulai berbau jika Anda memiliki Memformat accessors untuk segala jenis string yang Anda mungkin ingin cetak ( public string FirstLastName; public string FullName; public string FullNameWithMiddleInitial; public string PhoneNumberWithAreaCode; public string PhoneNumberWithoutAreaCode; public string PhoneNumberWithCountryCode;, dll)

Atau, dengan kata lain, menggunakan pola tidak secara otomatis membuat kode Anda memiliki "bau pola". Anda perlu menyalahgunakannya jika Anda ingin mendapatkan atribut itu.

Greg Jackson
sumber
Terima kasih, Greg. +1. Saya setuju dengan Anda tentang menempatkan setiap kombinasi. Saya benar-benar hanya mencoba menemukan cara terbersih untuk menstandarkan bagaimana data dilihat.
devuxer
3

Melanggar prinsip tanggung jawab tunggal. Mengapa tidak membuat kelas nomor telepon, dll ...?

Edward Strange
sumber
Oke, saya sebenarnya setuju dengan itu (lihat diskusi di bawah jawaban ammoQ), tetapi haruskah saya juga membuat FullNamekelas?
devuxer
Ya, Anda harus, tetapi Anda harus memperbaiki ejaan dari "FullName" ke "FoolName". Atau mungkin "PersonalName", karena itu adalah nama seseorang, dan bukan nama lengkap.
kevin cline
1
Betulkah? Kecuali jika kelas yang diberikan diharapkan untuk tumbuh, apa sebenarnya yang salah dengannya? Bahkan jika itu tumbuh, seberapa sulitkah itu untuk faktor ulang?
Pekerjaan
@DanM: Lalu itulah yang Anda minta, yaitu minta mereka untuk mengetikkan nama lengkap mereka. Jika Anda mengurutkan berdasarkan nama depan, Anda benar-benar mengurutkan pada huruf pertama (kemudian yang kedua, dan seterusnya) dari nama pertama (kemudian yang berikutnya, kemudian seterusnya), sehingga nama-nama akan mengurutkan yang sama terlepas.
Matt Ellen
@DanM, mari kita lanjutkan diskusi ini dalam obrolan
Matt Ellen
1

Sebagai contoh Anda, saya tidak melihatnya sebagai masalah besar untuk menggunakan format tertentu. Ini satu atau dua dan semua bagian aplikasi menggunakan format yang sama.

Di mana keputusan itu akan mulai rusak adalah ketika Anda memiliki data yang sama pergi ke beberapa tempat berbeda yang membutuhkan format yang berbeda .

Jika itu terjadi, saya akan tergoda untuk menarik Memberkelas kembali ke:

public class Member
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }  
}

Dan kemudian lakukan adapter yang berbeda untuk setiap target. Misalnya, anggap informasi itu diperlukan dalam format CSV:

public static class CSVMemberAdapter
{
    public static string ToCSV(this Member mbr)
    {
         return mbr.Id + "," + mbr.LastName + "," + mbr.FirstName, "," mbr.PhoneNumber;
    }
}

Selalu berasumsi bahwa Anda telah membersihkan data sehingga tidak ada koma, dll.

Adaptor tidak harus menjadi metode ekstensi, tetapi untuk kasus ini sepertinya cocok.

Peter K.
sumber
Sudah lama sejak saya menulis C #, tapi pasti ada kelas serialisasi yang bisa menangani ini, alih-alih menulis metode membosankan seperti toCSV berulang-ulang dan berulang-ulang dan berulang-ulang dan terus-menerus dan lagi dan lagi dan lagi dan lagi ...
kevin cline
@kevin cline: Tergantung pada apa yang Anda butuhkan di setiap wastafel. Jika semua yang mereka butuhkan adalah XML serial, baiklah. Banyak sistem tidak. Jika harus dilakukan oversebanyak itu, maka ada yang salah dengan desainnya.
Peter K.
biasanya akan ada banyak kelas untuk diserialisasi. Seharusnya dimungkinkan untuk menulis CSV tunggal atau serializer lain yang dapat menangani sebagian besar kelas melalui refleksi, daripada mengkodekan tangan seperti contoh Anda.
kevin cline
@kevin cline: Sangat setuju! Saya hanya menulis sesuatu yang sangat spesifik untuk pertanyaan yang diajukan. Contoh konkret dan sederhana cenderung menjelaskan sesuatu dengan lebih baik.
Peter K.