Saya bekerja dalam sistem yang dapat mewakili "perkiraan pengiriman" dalam dua cara:
- Tanggal tertentu: Barang dijamin dikirim pada tanggal itu
- Interval hari: Item akan dikirim hari "X ke Y" mulai hari ini
Informasi pada model secara semantik sama, itu adalah "perkiraan pengiriman". Ketika saya mendapatkan informasi tentang perkiraan pengiriman dari sistem, saya dapat mengetahui apakah perkiraan itu dari bentuk pertama atau bentuk kedua.
Model saat ini untuk ini mirip dengan yang berikut:
class EstimattedShippingDateDetails
{
DateTime? EstimattedShippingDate {get; set;}
Range? EstimattedShippingDayRange {get; set;}
}
Range
adalah kelas sederhana untuk membungkus "awal -> akhir" dari bilangan bulat, agak seperti ini:
struct Range
{
int Start {get; set}
int End {get; set}
public override ToString()
{
return String.Format("{0} - {1}", Start, End);
}
}
Saya tidak suka pendekatan ini karena hanya satu dari properti pada model estimasi yang akan diisi, dan saya perlu menguji nol pada salah satu dari mereka dan menganggap yang lain memiliki data.
Masing-masing properti ditampilkan secara berbeda kepada pengguna tetapi di tempat yang sama di UI, menggunakan MVT DisplayTemplate kustom, di mana logika switching saat ini berada:
@Model EstimattedShippingDateDetails
@if (Model.EstimattedShippingDate.HasValue)
{
Html.DisplayFor(m => Model.EstimattedShippingDate)
}
else
{
Html.DisplayFor(m => Model.EstimattedShippingDayRange)
}
Bagaimana saya bisa memodelkan ini untuk membuatnya lebih representatif dari persyaratan aktual sambil tetap menjaga logika tampilan tetap sederhana dalam aplikasi MVC?
Saya berpikir tentang menggunakan antarmuka dan dua implementasi, satu untuk setiap "jenis" estimasi, tetapi saya tidak bisa membungkus kepala saya di sekitar antarmuka umum untuk keduanya. Jika saya membuat antarmuka tanpa anggota, maka saya tidak dapat mengakses data secara terpadu dan ini adalah desain IMHO yang buruk. Saya juga ingin menjaga viewmodel sesederhana mungkin. Saya akan mendapatkan kode "benar berdasarkan konstruksi" dengan pendekatan ini, karena tidak perlu ada nullable lagi: setiap implementasi akan memiliki properti yang tidak dapat dibatalkan, baik a DateTime
atau a Range
.
Saya juga dianggap hanya menggunakan satu Range
dan ketika situasi # 1 terjadi, cukup gunakan yang sama DateTime
untuk keduanya Start
dan End
, tetapi ini akan menambah komplikasi tentang cara memancarkan nilai-nilai ke UI karena saya kemudian harus mendeteksi apakah itu statis atau interval oleh membandingkan nilai-nilai dan memformat rentang dengan benar untuk ditampilkan sebagai tanggal tunggal atau interval yang diformat.
Tampaknya apa yang saya butuhkan adalah konsep yang mirip dengan serikat pekerja Script: pada dasarnya properti yang bisa dari dua jenis. Tidak ada hal seperti itu ada di C # tentu saja (hanya dynamic
akan dekat dengan itu).
sumber
Jawaban:
Gunakan rentang tanggal (yaitu dua tanggal) untuk semua perkiraan pengiriman.
Untuk satu kencan, jadikan X dan Y sama dengan.
sumber
DateTime
objek, mewakili tanggal pengiriman yang diharapkan, atau dua nilai integer dengan hari minimum dan maksimum mulai hari ini bahwa barang akan dikirim. Jika saya membakukan tanggal, saya harus mengubah bilangan bulat tersebut menjadi DateTimes yang dibangun dengan benar, yang akan sedikit menambah kerumitan karena segala sesuatu yang perlu diperhitungkan, seperti tanggal klien vs server, UTC, waktu musim panas perbedaan dll. Saya ingin menghindari menciptakan kompleksitas semacam ini pada saat ini.Anda dapat memodelkan ini menggunakan enkapsulasi.
Biarkan kelas memiliki 2 konstruktor, satu untuk satu tanggal dan satu lagi untuk rentang tanggal.
Dalam metode ToString () menentukan 'status' kelas dan menghasilkan string yang diformat yang sesuai.
Tambahkan metode lain yang sesuai untuk kebutuhan Anda yang lain.
sumber
Range
jenisnya dapat digunakan di tempat lain pada sistem dan dalam hal ini ditampilkan dengan cara yang sama. Itu sebabnya saya perlu memusatkanRange
tampilan menjadi DisplayTemplate yang dapat digunakan kembali. Jika saya menggunakanToString
metode ini untuk merangkum hal itu, saya kehilangan banyak fleksibilitas yang disediakan oleh view.state
.ToString()
seharusnya hanya "melaporkan" negara. Negara ditentukan dalam konstruktor, properti setter, dan sebagainya. Dan, saya hanya tidak melihat apa pun di OP yang menunjukkan ada atau harusnya "ringkasan negara"Ini adalah masalah yang cukup umum, Nullables misalnya menyelesaikan masalah umum tempat tanggal berakhirnya hal-hal yang belum berakhir.
Tapi saya pikir Anda telah memilih contoh yang buruk.
Dengan kasus persis dua kencan Anda, rentang tanggal yang dimulai di pagi hari dan berakhir di malam hari tampaknya menjadi solusi yang sempurna. Atau mungkin tanggal awal dan bilangan bulat hari tambahan mungkin?
Namun, mari kita pertimbangkan kasus yang lebih sulit. Saya memiliki dua jenis pengiriman, pos dan pengambilan dari toko. Ini adalah obvs yang jauh lebih berbeda, toko membutuhkan nama dan alamat, pos memiliki biaya, mungkin sejumlah opsi pengiriman, kode pelacakan dll.
Pendekatan standar adalah untuk mencari hal-hal umum yang membuat kedua 'opsi pengiriman' ini dan menempatkan mereka di kelas dasar. Subkelas dua kasus khusus dengan rincian tambahan yang mereka miliki / butuhkan.
Dalam hampir semua kasus, Anda akan memiliki setidaknya Id, Jenis, dan Deskripsi yang umum untuk kedua jenis. Begitu:
sumber
DataTime.Date
properti dan jangan khawatir tentang waktu sama sekali."start" dan "end" bukan DateTime, Itu Offsets
"start" dan "end" adalah offset ke
EstimatedShipDate
. Mereka bukan milikDateTime
mereka sendiri . Ini lebih baik menggambarkan apa yang terjadi dan secara dramatis akan mengurangi kompleksitas.Tidak perlu untuk
interface
. Tidak perluRange
kelas. Jangan membuat kerumitan sampai Anda yakin Anda membutuhkannya. Saya sangat curiga bahwa satu kelas dengan konstruktor 3-opsional-parameter akan menjaga hal-hal lebih sederhana.Gunakan satu konstruktor yang melewatkan ketiga nilai melalui parameter opsional. Ini memasok semua konteks yang dibutuhkan. The tunggal logika konstruktor kemudian dapat mengevaluasi untuk semua variasi untuk mengatur keadaan awal dengan benar. Juga gunakan parameter bernama dalam panggilan konstruktor jika diinginkan untuk membuatnya sejernih kristal.
Tidak. Jangan lakukan ini dan semuanya lebih sederhana; alih-alih gunakan DateTime.AddDays () `.
Ini berpotensi lebih fleksibel jika tanggal dan nilai offset diizinkan untuk berubah.
Baca tentang penanganan zona waktu di sini.
Untuk saat ini cukup sertakan
DateTime.DateTimeKind
parameter konstruktor (enum) dan tangani nanti.Dari salah satu jawaban:
Gunakan
DateTime.Date
properti dan abaikan waktu sepenuhnya.sumber
Bagaimana dengan sesuatu
Keduanya
EarliestShippingDate
danLatestShippingDate
diatur ke tanggal pengiriman yang dijamin.EarliestShippingDate
diatur ke hari ini danLatestShippingDate
diatur ketoday + (Y - X)
sumber
Anda perlu memutuskan apa perbedaan (jika ada) antara tanggal pengiriman tunggal, dan rentang yang terdiri dari satu hari. Jika "tanggal pengiriman tunggal" hanya rentang hari yang terdiri dari satu hari, maka modelkan semuanya sebagai tanggal mulai dan tanggal berakhir. Jika "tanggal pengiriman tunggal" dan rentang hari dengan tanggal mulai dan berakhir yang sama harus diperlakukan secara berbeda maka simpan salah satu dari dua kasus, baik tanggal tunggal untuk tanggal pengiriman tunggal, dan dua tanggal untuk rentang hari .
sumber
Pada dasarnya Anda memiliki 2 opsi:
2 tanggal. Jika objek mewakili satu tanggal, atur keduanya ke nilai yang sama, atau atur tanggal ke-2 menjadi nilai nol.
1 tanggal dan jangka waktu. Tanggal mewakili awal, dan rentang waktu menunjukkan seberapa banyak rentang di masa depan. Tetapkan rentang ke 0 untuk satu tanggal.
Untuk pengiriman saya akan memiliki datetime daripada tanggal karena Anda tidak akan ragu ingin memodelkan pengiriman pagi / malam. Yang mana dari 2 opsi yang terbaik tergantung bagaimana Anda ingin menghitung tampilan. Jika Anda menampilkan "antara x dan y" maka opsi pertama mungkin lebih mudah digunakan, jika Anda menampilkan "hingga x hari dari y" maka yang terakhir lebih mudah digunakan.
Jika Anda tidak menyukai nilai nol maka opsi terakhir lebih baik, karena menghitung tanggal asli ditambah rentang waktu dapat dilakukan terlepas dari apakah rentang waktu memiliki nilai atau diatur ke 0. Anda akan selalu mendapatkan hasil yang benar tanpa memeriksa nol.
sumber