开发者

Enterprise Design Pattern Question

开发者 https://www.devze.com 2023-01-27 16:50 出处:网络
Something on my mind ab开发者_如何学Goout structuring a system at a high level. Let\'s say you have a system with the following layers:

Something on my mind ab开发者_如何学Goout structuring a system at a high level.

Let's say you have a system with the following layers:

  • UI
  • Service Layer
  • Domain Model
  • Data Access

The service layer is used to populate a graph of objects in the domain model. In an attempt to avoid coupling, the domain model will be not be persistence aware and will not have any dependencies on any data access layer.

However, using this approach how would one object in the domain model be able to call other objects without being able to load them with persistence, thus coupling everything together - which I'd be trying to avoid.

e.g. an Order Object would need to check an Inventory object and would obviously need to tell the Inventory object to load in some way, or populate it somehow.

Any thoughts?


You could inject any dependencies from the service layer, including populated object graphs.

I would also add that a repository can be a dependency - if you have declared an interface for the repository, you can code to it without adding any coupling.


One way of doing this is to have a mapping layer between the Data Layer and the domain model.

Have a look at the mapping, repository and facade patterns.

The basic idea is that on one side you have data access objects and on the other you have domain objects.


To decouple you have to: "Program to an 'interface', not an 'implementation'." (Gang of Four 1995:18)

Here are some links on the subject:

Gamma interview on patterns

Random blog article

Googling for "Program to an interface, not an implementation" will yield many useful resources.


Have the domain model layer define interfaces for the methods you'll need to call, and POCOs for the objects that need to be returned by those methods. The data layer can then implement those interfaces by pulling data out of your data store and mapping it into the domain model POCOs.

Any domain-level class that requires a particular data-access service can just depend on the interface via constructor arguments. Then you can leverage a dependency-injection framework to build the dependency graph and provide the correct implementations of your interfaces wherever they are required.


Before writing tons of code in order to separate everything you might want to ask yourself a few questions:

  1. Is the Domain Model truly separate from the DAL? And yes, I'm serious and you should think about this because it is exceedingly rare for an RDBMS to actually be swapped out in favor of a different one for an existing project. Quite frankly it is much more common for the language the app was written in to be replaced than the database itself.

  2. What exactly is this separation buying you? And, just as important, what are you losing? Separation of Concerns (SoC) is a nice term that is thrown about quite a bit. However, most people rarely understand why they are Concerned with the Separation to begin with.

I bring these up because more often than not applications can benefit from a tighter coupling to the underlying data model. Never mind that most ORM's almost enforce a tight coupling due to the nature of code generation. I've seen lot's of supposedly SoC projects come to a crash during testing because someone added a field to a table and the DAL wasn't regenerated... This kind of defeats the purpose, IMHO...

Another factor is where should the business logic live? No doubt there are strong arguments in favor of putting large swaths of BL in the actual database itself. At the same time there are cases where the BL needs to live in or very near your domain classes. With BL spread in such a way, can you truly separate these two items anyway? Even those who hate the idea of putting BL in a database will fall back on using identity keys and letting the DB enforce referential integrity, which is also business logic..

Without knowing more, I would suggest you consider flattening the Data Access and Domain Model layers. You could move to a "provider" or "factory" type architecture in which the service layer itself doesn't care about the underlying access, but the factory handles it all. Just some radical food for thought.


You should take a look at Martin Fowler's Repository and UnitOfWork patterns to use interfaces in your system


Until now I have seen that application can be well layered into three layers: Presentation-->Logic-->Data--and Entities (or Bussines Object). In the Logic Layer case you can use some pattern such as Transaction Script or Domain Model I'm supposing you're using this last. The domain model can use a Data Mapper for interacting with the data layer and create business objects, but you can also use a Table Module pattern.

All this patterns are described in Marttin's Fowler Patterns of Enterprise Application Architecture book. Personally I use Transaction Script because it is simplest than Domanin Model.


One solution is to make your Data Access layer subclass your domain entities (using Castle DynamicProxy, for example) and inject itself into the derived instances that it returns.

That way, your domain entity classes remain persistence-ignorant while the instances your applications use can still hit databases to lazy-load secondary data.

Having said that, this approach typically requires you to make a few concessions to your ORM's architecture, like marking certain methods virtual, adding otherwise unnecessary default constructors, etc..

Moreover, it's often unnecessary - especially for line-of-business applications that don't have onerous performance requirements, you can consider eagerly loading all the relevant data: just bring the inventory items up with the order.


I felt this was different enough from my previous answer, so here's a new one.

Another approach is to leverage the concept of Inversion of Control (IoC). Build an Interface that your Data Access layer implements. Each of the DAL methods should take a list of parameters and return a Data Table.

The service layer would instantiate the DAL through the interface and pass that reference to your Domain Model. The domain model would then make it's own calls into the DAL, using the interface methods, and decide when it needs to load child objects or whatever.

Something like:

interface IDBModel {
  DataTable LoadUser(Int32 userId);
}

class MyDbModel : IDBModel {
  DataTable LoadUser(Int32 userId) {
    // make the appropriate DB calls here, return a data table
  }
}

class User {
  public User(IDBModel dbModel, Int32 userId) {
    DataTable data = dbModel.LoadUser(userId);
    // assign properties.. load any additional data as necessary
  }
// You can do cool things like call User.Save() 
// and have the object validate and save itself to the passed in 
// datamodel.  Makes for simpler coding.
}

class MyServiceLayer {
  public User GetUser(Int32 userId) {
    IDBModel model = new MyDbModel();

    return new User(model, userId);
  }
}

With this mechanism, you can actually swap out your db models on demand. For example, if you decide to support multiple databases then you can have code that is specific to a particular database vendors way of doing things and just have the service layer pick which one to use.

The domain objects themselves are responsible for loading their own data and you can keep any necessary business logic within the domain model. Another point is that the Domain Model doesn't have a direct dependency on the data layer, which preserves your mocking ability for independent testing of business logic.

Further, the DAL has no knowledge of the domain objects, so you can swap those out as necessary or even just test the DAL independently.

0

精彩评论

暂无评论...
验证码 换一张
取 消