Domain Driven Design question
I'm new to DDD so please forgive me 开发者_如何学Goif I'm not using the terms correctly.
I am Using C# MS/SQL and NHibernate.
I have a class call Payment and this payment has a PaymentCurrency each of these is an entity in the database.
OK. In my Domain Model I want to be able to create Payment as Either
Payment p = new Payment( 100 ) // automatically uses the default currency (defined in the db )
or
Payment p = new Payment( 100, Repository.GetCurrency( "JPY" ) ) // uses Yen defined in the db.
But it seems to me that in order to initialize my Domain Object with the dfault currency I need to pollute the domain model with knowledge of persistance. i.e. before I can completed the default Payment Constructor I need to load the Default Payment object from the db.
The constructor I visualize is somehting like
public Payment( int amount ) {
Currency = Repository.LoadDefaultCurrency(); // of cource defualt currency would be a singleton
}
public Payment( int amount, Currency c ) {
Currency = c; // this is OK since c is passed in from outside the domain model.
}
Thanks for your advice.
I don't think there's a perfect solution to this, but you can avoid putting the persistence code into domain classes by having the default currency (and similar properties) stored on some other class (eg. "DomainDefaults") and have it initialised from another piece of code that logically sits "above" the domain objects. Of course, you'd have to make sure that initialisation code is called before any domain objects can be created. It should probably throw an exception if not initialised, so you can at least catch this easily.
So the constructor becomes
public Payment( int amount )
{
Currency = DomainDefaults.DefaultCurrency;
}
And somewhere soon after you initialise NHibernate you'd call:
DomainDefaults.DefaultCurrency = Repository.GetCurrency("JPY")
I don't see why this has to have anything to do with persistence at all.
If I were writing this in Java, I'd get the default currency from the Locale for the application.
This SO question tells me that CultureInfo is the C# equivalent. Maybe you should try that in your design, and leave strings like "JPY" and persistence out of it.
Your answer would be dependency injection.
Make use of it and don't polute model with configuration. If you need to create a payment with required Amount and Currency - just do exactly that:
var currency = injectedCurrencyRepository.GetByName("JPY");
var p = new Payment(100.00m, currency);
Do not assume default currency.
or at the worst end you can add inteface:
public interface ICurrencyProvider {
Currency GetCurrency();
}
// Implment the default:
public class DefaultCurrencyProvider : ICurrencyProvider {
public Currency GetCurrency() {
return new Currency("AUD");
}
}
// And the Payment constructor will look like:
public Payment(decimal amount, ICurrencyProvider currencyProvider) {
c = currencyProvider.GetCurrency();
}
so you can INJECT (using Windsot, Unity or whatever) that currency provider by default into method where you instantiate Payment:
var p = new Payment(100.00m, defaultCurrencyProvider);
精彩评论