Saya tahu Anda berpikir (atau mungkin berteriak), "bukan pertanyaan lain yang menanyakan di mana validasi berada dalam arsitektur berlapis?!?" Ya, tapi mudah-mudahan ini akan menjadi sedikit berbeda dalam hal ini.
Saya sangat percaya bahwa validasi mengambil banyak bentuk, berbasis konteks dan bervariasi di setiap tingkat arsitektur. Itu adalah dasar untuk pos - membantu mengidentifikasi jenis validasi apa yang harus dilakukan di setiap lapisan. Selain itu, pertanyaan yang sering muncul adalah di mana cek otorisasi berada.
Skenario contoh berasal dari aplikasi untuk bisnis katering. Secara berkala di siang hari, pengemudi dapat menyerahkan ke kantor kelebihan uang tunai yang telah mereka kumpulkan saat membawa truk dari lokasi ke lokasi. Aplikasi ini memungkinkan pengguna untuk merekam 'setetes uang tunai' dengan mengumpulkan ID pengemudi, dan jumlahnya. Berikut beberapa kode kerangka untuk menggambarkan lapisan yang terlibat:
public class CashDropApi // This is in the Service Facade Layer
{
[WebInvoke(Method = "POST")]
public void AddCashDrop(NewCashDropContract contract)
{
// 1
Service.AddCashDrop(contract.Amount, contract.DriverId);
}
}
public class CashDropService // This is the Application Service in the Domain Layer
{
public void AddCashDrop(Decimal amount, Int32 driverId)
{
// 2
CommandBus.Send(new AddCashDropCommand(amount, driverId));
}
}
internal class AddCashDropCommand // This is a command object in Domain Layer
{
public AddCashDropCommand(Decimal amount, Int32 driverId)
{
// 3
Amount = amount;
DriverId = driverId;
}
public Decimal Amount { get; private set; }
public Int32 DriverId { get; private set; }
}
internal class AddCashDropCommandHandler : IHandle<AddCashDropCommand>
{
internal ICashDropFactory Factory { get; set; } // Set by IoC container
internal ICashDropRepository CashDrops { get; set; } // Set by IoC container
internal IEmployeeRepository Employees { get; set; } // Set by IoC container
public void Handle(AddCashDropCommand command)
{
// 4
var driver = Employees.GetById(command.DriverId);
// 5
var authorizedBy = CurrentUser as Employee;
// 6
var cashDrop = Factory.CreateCashDrop(command.Amount, driver, authorizedBy);
// 7
CashDrops.Add(cashDrop);
}
}
public class CashDropFactory
{
public CashDrop CreateCashDrop(Decimal amount, Employee driver, Employee authorizedBy)
{
// 8
return new CashDrop(amount, driver, authorizedBy, DateTime.Now);
}
}
public class CashDrop // The domain object (entity)
{
public CashDrop(Decimal amount, Employee driver, Employee authorizedBy, DateTime at)
{
// 9
...
}
}
public class CashDropRepository // The implementation is in the Data Access Layer
{
public void Add(CashDrop item)
{
// 10
...
}
}
Saya telah menunjukkan 10 lokasi tempat saya melihat pemeriksaan validasi ditempatkan dalam kode. Pertanyaan saya adalah pemeriksaan apa yang akan Anda lakukan, jika ada, berkinerja di masing-masing diberi aturan bisnis berikut (bersama dengan pemeriksaan standar untuk panjang, rentang, format, jenis, dll):
- Jumlah penurunan uang tunai harus lebih besar dari nol.
- Setetes tunai harus memiliki Driver yang valid.
- Pengguna saat ini harus diberi wewenang untuk menambahkan tetes uang tunai (pengguna saat ini bukan pengemudi).
Silakan bagikan pemikiran Anda, bagaimana Anda memiliki atau akan mendekati skenario ini dan alasan untuk pilihan Anda.
CashDropAmount
objek nilai daripada menggunakan a Decimal
. Memeriksa apakah driver ada atau tidak akan dilakukan dalam penangan perintah dan hal yang sama berlaku untuk aturan otorisasi. Anda bisa mendapatkan otorisasi secara gratis dengan melakukan sesuatu seperti di Approver approver = approverService.findById(employeeId)
mana ia dilemparkan jika karyawan tidak dalam peran pemberi persetujuan. Approver
hanya akan menjadi objek nilai, bukan entitas. Anda juga bisa menyingkirkan pabrik atau penggunaan metode pabrik Anda pada AR sebagai gantinya: cashDrop = driver.dropCash(...)
.