您的位置:首页 > 编程语言 > ASP

Pro ASP.NET MVC - [3]Prerequisites(前提) - [2]Domain Modeling

2009-10-09 15:35 225 查看

Domain Modeling

You've already seen how it makes sense to take the real-world objects, processes, and rules from your software's subject matter and encapsulate(囊括) them in a component called a domain model. This component is the heart of your software; it's your software's universe(体系). Everything else (including controllers and views) is just a technical detail designed to support or permit interaction with the domain model. Eric Evans, a leader in domain-driven design (DDD), puts it well:

"The part of the software that specifically(专门地) solves problems from the domain model usually constitutes(组成) only a small portion of the entire software system, although its importance is disproportionate(不成比例的) to its size. To apply our best thinking, we need to be able to look at the elements of the model and see them as a system. We must not be forced to pick them out of a much larger mix of objects, like trying to identify(识别) constellations(星座) in the night sky. We need to decouple(解耦) the domain objects from other functions of the system, so we can avoid confusing(混淆) domain concepts with concepts related only to software technology or losing sight of the domain altogether in the mass of the system."

ASP.NET MVC contains no specific technology related to domain modeling (instead relying on(依靠) what it inherits(继承) from the .NET Framework and ecosystem), so this book has no chapter on domain modeling. Nonetheless, modeling is the Min MVC, so I cannot ignore the subject altogether. For the next portion of this chapter, you'll see a quick example of implementing a domain model with .NET and SQL Server, using a few of the core techniques from DDD.

An Example Domain Model

No doubt you've already experienced the process of brainstorming a domain model in your previous projects. Typically, it involves(牵涉) one or more developers, one or more business experts, a whiteboard, and a lot of cookies. After a while, you'll pull together a first-draft(草案初稿) model of the business processes you're going to automate. For example, if you were going to implement an online auctions(拍卖) site, you might get started with something like that shown in Figure 3-4.

public class Member

public class Item

public class Bid

Notice that Bid is immutable (that's as close as you'll get to a true value object), and the other classes' properties are appropriately protected. These classes respect(尊重) aggregate boundaries in that no references violate the boundary rule. Note In a sense, a C# struct (as opposed to a class) is immutable, because each assignment(分配) creates a new instance, so mutations(变化) don't affect other instances. However, for a domain value object, that's not always the type of immutability you're looking for; you often want to prevent any changes happening to any instance (after the point of creation), which means all the fields must be read-only. A class is just as good as a struct for that, and classes have many other advantages (e.g., they support inheritance).

Is It Worth Defining Aggregates?

Aggregates bring superstructure(上层建筑) into a complex domain model, adding a whole extra level of manageability. They make it easier to define and enforce data integrity(完整的) rules (an aggregate root can validate the state of the entire aggregate). They give you a natural unit for persistence, so you can easily decide how much of an object graph to bring into memory (perhaps using lazy-loading for references to other aggregate roots). They're the natural unit for cascade deletion(级联删除), too. And since data changes are atomic within an aggregate, they're an obvious unit for transactions(事务). On the other hand, they impose restrictions(约束) that can sometimes seem artificial(人造的)—because they are artificial—and compromise(违背) is painful(痛苦的). They're not a native concept in SQL Server, nor in most ORM tools, so to implement them well, your team will need discipline and effective communication.

Keeping Data Access Code in Repositories

Sooner or later you'll have to think about getting your domain objects into and out of some kind of persistent storage—usually a relational database. Of course, this concern is purely a matter of today's software technology, and isn't part of the business domain you're modeling.

Persistence is an independent concern (real architects say orthogonal(垂直) concern—it sounds much cleverer), so you don't want to mix persistence code with domain model code, either by embedding database access code directly into domain entity methods, or by putting loading or querying code into static methods on those same classes.

The usual way to keep this separation clean is to define repositories. These are nothing more than object-oriented representations of your underlying relational database store (or file-based store, or data accessed over a web service, or whatever), acting as a facade over the real implementation. When you're working with aggregates, it's normal to define a separate repository for each aggregate, because aggregates are the natural unit for persistence logic. For example, continuing the auctions example, you might start with the following two repositories (note that there's no need for a BidsRepository, because bids need only be found by following references from item instances):

public class MembersRepository

public class ItemsRepository

using System;

using System.Collections.Generic;

using System.Linq;

using System.Data.Linq.Mapping;

using System.Data.Linq;

[Table(Name="Members")] public class Member

[Table(Name = "Items")] public class Item

[Table(Name = "Bids")] public class Bid

DataContext dc = new DataContext(connectionString); // Get a live DataContext

dc.GetTable<Member>(); // Tells dc it's responsible for persisting the class Member

dc.GetTable<Item>(); // Tells dc it's responsible for persisting the class Item

dc.GetTable<Bid>(); // Tells dc it's responsible for persisting the class Bid

dc.CreateDatabase(); // Causes dc to issue CREATE TABLE commands for each classRemember, though, that you'll have to perform any future schema updates manually, because CreateDatabase() can't update an existing database. Alternatively, you can just create the schema manually in the first place. Either way, once you've created a corresponding database schema, you can create, update, and delete entities using LINQ syntax and methods on System.Data.Linq.DataContext. Here's an example of constructing and saving a new entity:

DataContext dc = new DataContext(connectionString);
dc.GetTable<Member>().InsertOnSubmit(new Member
{
LoginName = "Steve",
ReputationPoints = 0
});
dc.SubmitChanges();
And here's an example of retrieving a list of entities in a particular order:

public class MembersRepository

public class ItemsRepository

ItemsRepository itemsRep = new ItemsRepository(connectionString);

itemsRep.AddItem(new Item

itemsRep.SubmitChanges();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: