轉(zhuǎn)帖|其它|編輯:郝浩|2010-11-09 13:24:38.000|閱讀 615 次
概述:在上一篇文章中,我們討論了兩種組織業(yè)務(wù)邏輯的模式:Transaction Script和Active Record。在本篇中開(kāi)始講述Domain Model和Anemic Model。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門(mén)軟控件火熱銷售中 >>
前言: 在上一篇文章中,我們討論了兩種組織業(yè)務(wù)邏輯的模式:Transaction Script和Active Record。在本篇中開(kāi)始講述Domain Model和Anemic Model。
注:不管技術(shù)的道路多么難走,我們還是得踏踏實(shí)實(shí)的把技術(shù)做下去。也希望朋友們能夠一如既往的支持本系列。
本篇議題如下:
Transaction Scrip(前篇)
Active Record前篇)
Domain Model(中篇)
Anemic Model(后篇)
DDD(后篇)
Domain Model:
在開(kāi)發(fā)過(guò)程中,我們常常用Domain Model來(lái)對(duì)目標(biāo)的業(yè)務(wù)領(lǐng)域建模。通過(guò)Domain Model建模的業(yè)務(wù)類代表了目標(biāo)領(lǐng)域中的一些概念。而且,我們會(huì)看到通過(guò)Domain Model建模的一些對(duì)象模擬了業(yè)務(wù)活動(dòng)中的數(shù)據(jù),有的對(duì)象還反映了一些業(yè)務(wù)規(guī)則。
我們就來(lái)看看電子商務(wù)系統(tǒng)的開(kāi)發(fā),在開(kāi)發(fā)中我們建立了一些概念的模型來(lái)反映電子商務(wù)領(lǐng)域中的一些概念:購(gòu)物車,訂單,訂單項(xiàng)等。這些模型有自己的數(shù)據(jù),行為。例如一個(gè)訂單模型,它不僅僅包含一些屬性(流水號(hào),創(chuàng)建日期,狀態(tài))來(lái)包含自己的數(shù)據(jù),同時(shí)它也包含了一些業(yè)務(wù)邏輯:下訂單的用戶時(shí)候合法,下訂單用戶的余額是否充足等。
一般來(lái)說(shuō),我們對(duì)領(lǐng)域了解的越深,我們?cè)谲浖薪⒌哪J皆浇咏F(xiàn)實(shí)中的概念,最后實(shí)現(xiàn)的軟件就越符合客戶的需求。同時(shí)在建模的過(guò)程中,也要考慮模型的可實(shí)現(xiàn)行,可能我們對(duì)領(lǐng)域進(jìn)行了很好的建模,和符合目標(biāo)領(lǐng)域的一些概念,但是在軟件實(shí)現(xiàn)起來(lái)非常的困難,那么就得權(quán)衡一下:找出一個(gè)比較好的模式,同時(shí)也便于實(shí)現(xiàn)。
在以前的文章中其實(shí)也提到過(guò)一些有關(guān)Domain Model的一些東西,其實(shí)Domain Model和Active Record的一個(gè)區(qū)別在于:Domain Model不知道自己的數(shù)據(jù)時(shí)如何持久化的,即PI(Persistence Ignorance).也就是說(shuō),通過(guò)Domain Model建立的業(yè)務(wù)類,都是POCO(Plain Old Common Runtime Object)。
下面我們就用一個(gè)銀行轉(zhuǎn)賬的例子來(lái)講述一下Domain Model的應(yīng)用。
創(chuàng)建一個(gè)新的解決方案,命名為ASPPatterns.Chap4.DomainModel,并且添加如下的項(xiàng)目:
ASPPatterns.Chap4.DomainModel.Model
ASPPatterns.Chap4.DomainModel.AppService
ASPPatterns.Chap4.DomainModel.Repository
ASPPatterns.Chap4.DomainModel.UI.Web
編譯整個(gè)Solution,然后添加引用:
為Repository項(xiàng)目添加Model 的引用
為AppService項(xiàng)目添加Model和Repository的引用、
為Web項(xiàng)目添加AppService的引用
下面就來(lái)看看每個(gè)項(xiàng)目代表的含義:
ASPPatterns.Chap4.DomainModel.Model:在這個(gè)project中包含了系統(tǒng)中所有的業(yè)務(wù)邏輯和業(yè)務(wù)對(duì)象,以及業(yè)務(wù)對(duì)象之間的關(guān)系。這個(gè)project也定義了持久化業(yè)務(wù)對(duì)象的接口,并且用Repository 模式來(lái)實(shí)現(xiàn)的(Repository 模式我們后面會(huì)談到的)。大家可以看到:這個(gè)Model的project沒(méi)有引用其他的project,也就是說(shuō)這個(gè)Model的project完全關(guān)注于業(yè)務(wù)。
ASPPatterns.Chap4.DomainModel.Repository:這個(gè)Repository的project實(shí)現(xiàn)了包含在Model project中定義的持久化接口。而且Repository還引用了Model project,就是用來(lái)持久化Model的數(shù)據(jù)的。
ASPPatterns.Chap4.DomainModel.AppService:AppService project就扮演者一個(gè)應(yīng)用層的角色,或者理解為門(mén)戶入口,因?yàn)樘峁┝艘恍┍容^粗顆粒度的API,并且它和Presenter層之間通過(guò)消息的機(jī)制來(lái)進(jìn)行通信。(消息模式我們以后也會(huì)講述)而且在AppService中,我們還會(huì)定義一些view model,這些view model的就符合也最后要顯示的數(shù)據(jù)結(jié)構(gòu),view model的數(shù)據(jù)可能是很多業(yè)務(wù)對(duì)象數(shù)據(jù)的組合,或者僅僅就是這業(yè)務(wù)對(duì)象數(shù)據(jù)的格式轉(zhuǎn)換等等。
ASPPatterns.Chap4.DomainModel.UI.Web:這個(gè)Web.UI project主要是負(fù)責(zé)最后的顯示邏輯和一些用戶體驗(yàn)的實(shí)現(xiàn)。這個(gè)project就調(diào)用AppService提供的API,獲取符合界面顯示的強(qiáng)類型的view model,然后顯示數(shù)據(jù)。
系統(tǒng)的這整個(gè)結(jié)構(gòu)如下:
下面就開(kāi)始創(chuàng)建保存數(shù)據(jù)的數(shù)據(jù)庫(kù),和以前一樣,為了演示的作用,我們?cè)赪eb project中添加一個(gè)名為BankAccount.mdf的數(shù)據(jù)庫(kù),并且建立如下的表:
BankAccount 表
Transaction 表
下一步就開(kāi)始為領(lǐng)域建模,因?yàn)檫@里的例子比較簡(jiǎn)單和常見(jiàn),建模的過(guò)程就省了,最后就得到了表示領(lǐng)域概念的兩個(gè)領(lǐng)域?qū)ο螅ɑ蛘哒f(shuō)業(yè)務(wù)對(duì)象):
public class Transaction
{
public Transaction(decimal deposit, decimal withdrawal, string reference, DateTime date)
{
this.Deposit = deposit;
this.Withdrawal = withdrawal;
this.Reference = reference;
this.Date = date;
}
public decimal Deposit
{ get; internal set; }
public decimal Withdrawal
{ get; internal set; }
public string Reference
{ get; internal set; }
public DateTime Date
{ get; internal set; }
}
在上面的代碼中,Transaction對(duì)象不包含任何的標(biāo)識(shí)屬性(標(biāo)識(shí)對(duì)象唯一的屬性,常常和數(shù)據(jù)庫(kù)中的表的主鍵對(duì)應(yīng)),因?yàn)門(mén)ransaction對(duì)象就是表示訂單中的每一筆交易,而且在這個(gè)系統(tǒng)中我們往往關(guān)心的只是每個(gè)Transaction的數(shù)據(jù),而不關(guān)系這個(gè)Transaction到底是那個(gè)Transaction。也就是說(shuō)此時(shí)在這個(gè)系統(tǒng)中Transaction是一個(gè)值對(duì)象(后篇講述DDD會(huì)提到)。
再看看BankAccount類:
public class BankAccount
{
private decimal _balance;
private Guid _accountNo;
private string _customerRef;
private IList<Transaction> _transactions;
public BankAccount() : this(Guid.NewGuid(), 0, new List<Transaction>(), "")
{
_transactions.Add(new Transaction(0m, 0m, "account created", DateTime.Now));
}
public BankAccount(Guid Id, decimal balance, IList<Transaction>
transactions, string customerRef)
{
AccountNo = Id;
_balance = balance;
_transactions = transactions;
_customerRef = customerRef;
}
public Guid AccountNo
{
get { return _accountNo; }
internal set { _accountNo = value; }
}
public decimal Balance
{
get { return _balance; }
internal set { _balance = value; }
}
public string CustomerRef
{
get { return _customerRef; }
set { _customerRef = value; }
}
public bool CanWithdraw(decimal amount)
{
return (Balance >= amount);
}
public void Withdraw(decimal amount, string reference)
{
if (CanWithdraw(amount))
{
Balance -= amount;
_transactions.Add(new Transaction(0m, amount, reference, DateTime.Now));
}
}
public void Deposit(decimal amount, string reference)
{
Balance += amount;
_transactions.Add(new Transaction(amount, 0m, reference, DateTime.Now));
}
public IEnumerable<Transaction> GetTransactions()
{
return _transactions;
}
}
代碼中包含了一些保存數(shù)據(jù)的業(yè)務(wù)屬性,同時(shí)還包含了三個(gè)簡(jiǎn)單的業(yè)務(wù)方法:
CanWithdraw:是否可以取款
Withdraw:取款
Deposit:存款
為了代碼的健壯性,在調(diào)用Withdraw方法的時(shí)候,如果取款的數(shù)量超過(guò)了存款的數(shù)額,那么就拋出一個(gè)余額不足的異常:InsufficientFundsException.其實(shí)這里到底是拋異常還是給出其他的返回值,主要是個(gè)人的選擇,沒(méi)有一定要,非要什么的。
public class InsufficientFundsException : ApplicationException
{
}
所以業(yè)務(wù)方法Withdraw修改如下:
最后就考慮下如何持久化業(yè)務(wù)對(duì)象的數(shù)據(jù)。在上面業(yè)務(wù)類的設(shè)計(jì)中,我們盡量的保持業(yè)務(wù)類的干凈------只包含業(yè)務(wù)邏輯,關(guān)系和業(yè)務(wù)的數(shù)據(jù)。至于數(shù)據(jù)從何而來(lái),最后如何保存,我們都委托給了一個(gè)Repository的接口IBankAccountRepository
public interface IBankAccountRepository
{
void Add(BankAccount bankAccount);
void Save(BankAccount bankAccount);
IEnumerable<BankAccount> FindAll();
BankAccount FindBy(Guid AccountId);
}
本系統(tǒng)是一個(gè)銀行轉(zhuǎn)賬的系統(tǒng),轉(zhuǎn)賬的操作不是一個(gè)業(yè)務(wù)對(duì)象就能夠獨(dú)立的完成的,往往需要多個(gè)業(yè)務(wù)類,以及數(shù)據(jù)持久化類的一些相互配合,這些操作放在任何一個(gè)業(yè)務(wù)類中都會(huì)把職責(zé)搞亂,而且后期的維護(hù)還得到處去找這個(gè)方法。所以我們?cè)跇I(yè)務(wù)層中又剝離一層service,其中service中的每個(gè)方法其實(shí)和需求中的用例有個(gè)對(duì)象關(guān)系,例如在需求中就有轉(zhuǎn)賬的一個(gè)用例,那么在service中就有一個(gè)Transfer轉(zhuǎn)賬的方法,這個(gè)方法把很多的業(yè)務(wù)對(duì)象組合在一起完成這個(gè)轉(zhuǎn)賬的流程,也就是說(shuō),在每個(gè)業(yè)務(wù)類中的業(yè)務(wù)方法都是原子性的,細(xì)顆粒度的,可以被重用,而在業(yè)務(wù)層的service的方法就是粗顆粒度的,目的是為調(diào)用者提供簡(jiǎn)化的API。
public class BankAccountService
{
private IBankAccountRepository _bankAccountRepository;
public BankAccountService(IBankAccountRepository bankAccountRepository)
{
_bankAccountRepository = bankAccountRepository;
}
public void Transfer(Guid accountNoTo,
Guid accountNoFrom, decimal amount)
{
BankAccount bankAccountTo = _
bankAccountRepository.FindBy(accountNoTo);
BankAccount bankAccountFrom = _
bankAccountRepository.FindBy(accountNoFrom);
if (bankAccountFrom.CanWithdraw(amount))
{
bankAccountTo.Deposit(amount, "From Acc " +
bankAccountFrom.CustomerRef + " ");
bankAccountFrom.Withdraw(amount, "Transfer To Acc " +
bankAccountTo.CustomerRef + " ");
_bankAccountRepository.Save(bankAccountTo);
_bankAccountRepository.Save(bankAccountFrom);
}
else
{
throw new InsufficientFundsException();
}
}
}
清楚了上面的之后,我們就把Repository那層實(shí)現(xiàn),其實(shí)因?yàn)槲覀冊(cè)跇I(yè)務(wù)層中使用的只是Repository的接口,至于采用哪種數(shù)據(jù)持久化方法可以替換的,例如如果用數(shù)據(jù)庫(kù)來(lái)保存數(shù)據(jù),我們可以選擇用Linq To Sql,ADO.NET,EF等。業(yè)務(wù)層不用關(guān)心這些的。
在下面,就用了最原始的ADO.NET來(lái)實(shí)現(xiàn)的,大家可以任意替換實(shí)現(xiàn)策略:(下面的代碼大家過(guò)過(guò)就行了,可以不用細(xì)看)
public class BankAccountRepository : IBankAccountRepository
{
private string _connectionString;
public BankAccountRepository()
{
_connectionString = ConfigurationManager.ConnectionStrings["BankAccountConnectionString"].ConnectionString;
}
public void Add(BankAccount bankAccount)
{
string insertSql = "INSERT INTO BankAccounts " +
"(BankAccountID, Balance, CustomerRef) VALUES " +
"(@BankAccountID, @Balance, @CustomerRef)";
using (SqlConnection connection =
new SqlConnection(_connectionString))
{
SqlCommand command = connection.CreateCommand();
command.CommandText = insertSql;
SetCommandParametersForInsertUpdateTo(bankAccount, command);
connection.Open();
command.ExecuteNonQuery();
}
UpdateTransactionsFor(bankAccount);
}
public void Save(BankAccount bankAccount)
{
string bankAccoutnUpdateSql = "UPDATE BankAccounts " +
"SET Balance = @Balance, CustomerRef= @CustomerRef " +
"WHERE BankAccountID = @BankAccountID;";
using (SqlConnection connection =
new SqlConnection(_connectionString))
{
SqlCommand command = connection.CreateCommand();
command.CommandText = bankAccoutnUpdateSql;
SetCommandParametersForInsertUpdateTo(bankAccount, command);
connection.Open();
command.ExecuteNonQuery();
}
UpdateTransactionsFor(bankAccount);
}
private static void SetCommandParametersForInsertUpdateTo(BankAccount bankAccount, SqlCommand command)
{
command.Parameters.Add(new SqlParameter("@BankAccountID", bankAccount.AccountNo));
command.Parameters.Add(new SqlParameter
("@Balance", bankAccount.Balance));
command.Parameters.Add(new SqlParameter("@CustomerRef", bankAccount.CustomerRef));
}
private void UpdateTransactionsFor(BankAccount bankAccount)
{
string deleteTransactionSQl = "DELETE Transactions WHERE BankAccountId =
@BankAccountId;";
using (SqlConnection connection =
new SqlConnection(_connectionString))
{
SqlCommand command = connection.CreateCommand();
command.CommandText = deleteTransactionSQl;
command.Parameters.Add(new SqlParameter
("@BankAccountID", bankAccount.AccountNo));
connection.Open();
command.ExecuteNonQuery();
}
string insertTransactionSql = "INSERT INTO Transactions " +
"(BankAccountID, Deposit, Withdraw, Reference, [Date]) VALUES " +
"(@BankAccountID, @Deposit, @Withdraw, @Reference, @Date)";
foreach (Transaction tran in bankAccount.GetTransactions())
{
using (SqlConnection connection =
new SqlConnection(_connectionString))
{
SqlCommand command = connection.CreateCommand();
command.CommandText = insertTransactionSql;
command.Parameters.Add(new SqlParameter("
@BankAccountID", bankAccount.AccountNo));
command.Parameters.Add(new SqlParameter("@Deposit", tran.Deposit));
command.Parameters.Add(new SqlParameter("@Withdraw", tran.Withdrawal));
command.Parameters.Add(new SqlParameter("@Reference", tran.Reference));
command.Parameters.Add(new SqlParameter("@Date", tran.Date));
connection.Open();
command.ExecuteNonQuery();
}
}
}
public IEnumerable<BankAccount> FindAll()
{
IList<BankAccount> accounts = new List<BankAccount>();
string queryString = "SELECT * FROM dbo.Transactions INNER JOIN " +
"dbo.BankAccounts ON dbo.Transactions.BankAccountId =
dbo.BankAccounts.BankAccountId " +
"ORDER BY dbo.BankAccounts.BankAccountId;";
using (SqlConnection connection =
new SqlConnection(_connectionString))
{
SqlCommand command = connection.CreateCommand();
command.CommandText = queryString;
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
accounts = CreateListOfAccountsFrom(reader);
}
}
return accounts;
}
private IList<BankAccount> CreateListOfAccountsFrom(IDataReader datareader)
{
IList<BankAccount> accounts = new List<BankAccount>();
BankAccount bankAccount;
string id = "";
IList<Transaction> transactions = new List<Transaction>();
while (datareader.Read())
{
if (id != datareader["BankAccountId"].ToString())
{
id = datareader["BankAccountId"].ToString();
transactions = new List<Transaction>();
bankAccount = new BankAccount(new Guid(id), Decimal.Parse
(datareader["Balance"].ToString()), transactions,
datareader["CustomerRef"].ToString());
accounts.Add(bankAccount);
}
transactions.Add(CreateTransactionFrom(datareader));
}
return accounts;
}
private Transaction CreateTransactionFrom(IDataRecord rawData)
{
return new Transaction(Decimal.Parse(rawData["Deposit"].ToString()),
Decimal.Parse(rawData["Withdraw"].ToString()),
rawData["Reference"].ToString(),
DateTime.Parse(rawData["Date"].ToString()));
}
public BankAccount FindBy(Guid AccountId)
{
BankAccount account;
string queryString = "SELECT * FROM dbo.Transactions INNER JOIN " +
"dbo.BankAccounts ON dbo.Transactions.BankAccountId =
dbo.BankAccounts.BankAccountId " +
"WHERE dbo.BankAccounts.BankAccountId = @BankAccountId;";
using (SqlConnection connection =
new SqlConnection(_connectionString))
{
SqlCommand command = connection.CreateCommand();
command.CommandText = queryString;
SqlParameter Idparam = new SqlParameter("
@BankAccountId", AccountId);
command.Parameters.Add(Idparam);
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
account = CreateListOfAccountsFrom(reader)[0];
}
}
return account;
}
}
到現(xiàn)在為止,數(shù)據(jù)訪問(wèn),業(yè)務(wù)邏輯都已經(jīng)完成了,最后的一步就是顯示數(shù)據(jù)了。
我們知道:最后在界面顯示的數(shù)據(jù)結(jié)構(gòu),很多的時(shí)候和我們業(yè)務(wù)對(duì)象的數(shù)據(jù)結(jié)構(gòu)是不一致的,這個(gè)時(shí)候我們就要進(jìn)行一定的轉(zhuǎn)換,生成符合界面需要的數(shù)據(jù)結(jié)構(gòu),盡量少的讓顯示層出來(lái)過(guò)多的邏輯。此時(shí)就引入View Model來(lái)解決問(wèn)題。
AppService就是一個(gè)門(mén)戶:向顯示層提供需要的數(shù)據(jù)。我們?cè)贏ppService中就處理數(shù)據(jù)結(jié)構(gòu)不一致的情況:添加兩個(gè)View Model:
public class TransactionView
{
public string Deposit { get; set; }
public string Withdrawal { get; set; }
public string Reference { get; set; }
public DateTime Date { get; set; }
}
public class BankAccountView
{
public Guid AccountNo { get; set; }
public string Balance { get; set; }
public string CustomerRef { get; set; }
public IList<TransactionView> Transactions { get; set; }
}
然后我們?cè)偬砑右恍┹o助的方法來(lái)進(jìn)行數(shù)據(jù)結(jié)構(gòu)的轉(zhuǎn)換,例如把Transaction轉(zhuǎn)為TranactionViewModel
public static class ViewMapper
{
public static TransactionView CreateTransactionViewFrom
(Transaction tran)
{
return new TransactionView
{
Deposit = tran.Deposit.ToString("C"),
Withdrawal = tran.Withdrawal.ToString("C"),
Reference = tran.Reference,
Date = tran.Date
};
}
public static BankAccountView CreateBankAccountViewFrom
(BankAccount acc)
{
return new BankAccountView
{
AccountNo = acc.AccountNo,
Balance = acc.Balance.ToString("C"),
CustomerRef = acc.CustomerRef,
Transactions = new List<TransactionView>()
};
}
}
可能現(xiàn)在我們是把這些project部署在一臺(tái)機(jī)器上,如果是考慮到以后的分布式的情況,我們決定讓顯示層和AppService用消息模式來(lái)通信:請(qǐng)求-響應(yīng)!
public abstract class ResponseBase
{
public bool Success { get; set; }
public string Message { get; set; }
}
其中Success表示方法調(diào)用是否成功,Message包含一些信息,如錯(cuò)誤信息等。
下面就是請(qǐng)求的消息對(duì)象:
public class TransferRequest
{
public Guid AccountIdTo { get; set; }
public Guid AccountIdFrom { get; set; }
public decimal Amount { get; set; }
}
public class WithdrawalRequest
{
public Guid AccountId { get; set; }
public decimal Amount { get; set; }
}
然后我們把上面的對(duì)象組合在一起,為顯示層提供最簡(jiǎn)化的服務(wù):
public class ApplicationBankAccountService
{
private BankAccountService _bankAccountService;
private IBankAccountRepository _bankRepository;
public ApplicationBankAccountService() :
this (new BankAccountRepository(), new BankAccountService
(new BankAccountRepository()))
{ }
public ApplicationBankAccountService
(IBankAccountRepository bankRepository,
BankAccountService bankAccountService)
{
_bankRepository = bankRepository;
_bankAccountService = bankAccountService;
}
public ApplicationBankAccountService
(BankAccountService bankAccountService,
IBankAccountRepository bankRepository)
{
_bankAccountService = bankAccountService;
_bankRepository = bankRepository;
}
public BankAccountCreateResponse CreateBankAccount(BankAccountCreateRequest bankAccountCreateRequest)
{
BankAccountCreateResponse bankAccountCreateResponse =
new BankAccountCreateResponse();
BankAccount bankAccount = new BankAccount();
bankAccount.CustomerRef = bankAccountCreateRequest.CustomerName;
_bankRepository.Add(bankAccount);
bankAccountCreateResponse.BankAccountId = bankAccount.AccountNo;
bankAccountCreateResponse.Success = true;
return bankAccountCreateResponse;
}
public void Deposit(DepositRequest depositRequest)
{
BankAccount bankAccount = _bankRepository.FindBy
(depositRequest.AccountId);
bankAccount.Deposit(depositRequest.Amount, "");
_bankRepository.Save(bankAccount);
}
public void Withdrawal(WithdrawalRequest withdrawalRequest)
{
BankAccount bankAccount = _bankRepository.FindBy
(withdrawalRequest.AccountId);
bankAccount.Withdraw(withdrawalRequest.Amount, "");
_bankRepository.Save(bankAccount);
}
public TransferResponse Transfer(TransferRequest request)
{
TransferResponse response = new TransferResponse();
try
{
_bankAccountService.Transfer(request.AccountIdTo,
request.AccountIdFrom, request.Amount);
response.Success = true;
}
catch (InsufficientFundsException)
{
response.Message = "There is not enough funds in account no: " +
request.AccountIdFrom.ToString();
response.Success = false;
}
return response;
}
public FindAllBankAccountResponse GetAllBankAccounts()
{
FindAllBankAccountResponse FindAllBankAccountResponse =
new FindAllBankAccountResponse();
IList<BankAccountView> bankAccountViews = new List<BankAccountView>();
FindAllBankAccountResponse.BankAccountView = bankAccountViews;
foreach (BankAccount acc in _bankRepository.FindAll())
{
bankAccountViews.Add(ViewMapper.CreateBankAccountViewFrom(acc));
}
return FindAllBankAccountResponse;
}
public FindBankAccountResponse GetBankAccountBy(Guid Id)
{
FindBankAccountResponse bankAccountResponse =
new FindBankAccountResponse();
BankAccount acc = _bankRepository.FindBy(Id);
BankAccountView bankAccountView =
ViewMapper.CreateBankAccountViewFrom(acc);
foreach (Transaction tran in acc.GetTransactions())
{
bankAccountView.Transactions.Add(ViewMapper.
CreateTransactionViewFrom(tran));
}
bankAccountResponse.BankAccount = bankAccountView;
return bankAccountResponse;
}
}
最后我們就是處理顯示層。
在本例子中,顯示層就是用傳統(tǒng)的ASP.NET來(lái)實(shí)現(xiàn)的,而且用了最簡(jiǎn)單的實(shí)現(xiàn),如果需要,大家可以采用MVP模式,這點(diǎn)在我的另一文章(走向ASP.NET架構(gòu)設(shè)計(jì)—第三章—分層設(shè)計(jì),初涉架構(gòu)(中篇) )中詳細(xì)的講述了,這里不在贅述,也希望大家見(jiàn)諒。
到這里Domain Model就基本講述完了,我們可以看出:當(dāng)軟件中的業(yè)務(wù)比較的負(fù)責(zé)的時(shí)候,我們用Domain Model可能比較的好。因?yàn)橛肈omain Model的時(shí)候,我們的把所有的精力主要關(guān)注在對(duì)業(yè)務(wù)領(lǐng)域的建模,把業(yè)務(wù)的概念抽象出來(lái),變?yōu)檐浖梢詫?shí)現(xiàn)的模型。其實(shí)抽象出業(yè)務(wù)模式不是那么容易的事情,往往必須對(duì)領(lǐng)域作出比較深入的分析才行。
同時(shí),在業(yè)務(wù)建模和可實(shí)現(xiàn)性之間要有權(quán)衡,有時(shí)候,我們把業(yè)務(wù)分析的很透,但是分析出來(lái)的概念無(wú)法轉(zhuǎn)為實(shí)現(xiàn),產(chǎn)生了“水至清則無(wú)魚(yú)”。希望大家多多的琢磨幾種組織業(yè)務(wù)邏輯模式的區(qū)別。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:博客園