Business Logic that involves One Row in a Single Database Table.
For Collection of Rows, we have Domain Services.
Business Logic means some Computations or Calculations. If it is some Filtering or Records, it should be done in the Data Access Layer rather than in Domain Layer or App. Service layer.
About Domain Model
All Martin Fowler Text Related to Domain Model is Applicable only to Entities. it is the DDD that discovers the further Patterns within the Domain Model like Entities and its Variations, VO and it variations, Domain Events and it variations, Factories and it variations,
For Collection of Rows, we have Domain Services.
Business Logic means some Computations or Calculations. If it is some Filtering or Records, it should be done in the Data Access Layer rather than in Domain Layer or App. Service layer.
About Domain Model
All Martin Fowler Text Related to Domain Model is Applicable only to Entities. it is the DDD that discovers the further Patterns within the Domain Model like Entities and its Variations, VO and it variations, Domain Events and it variations, Factories and it variations,
In Domain Model, Order Objects Corresponds to One Order. Business Methods work on just one Order. Order Class encapsulate the Domain Logic related to one Order.
Thinking is that, Order object is loaded based on the ID. All Business Methods related to a single Order are housed inside the Order Class.
Thinking is that, Order object is loaded based on the ID. All Business Methods related to a single Order are housed inside the Order Class.
Domain Logic that involves Collection of Orders goes into the Domain Services Class.
One of the key messages of object orientation is bundling the data with the behavior that uses it.
The traditional object-oriented approach is based on objects with identity, along the lines of Domain Model (116).
Thus, if we have an Employee class, any instance of it corresponds to a particular employee.
This scheme works well because once we have a reference to an employee, we can execute operations, follow relationships, and gather data on him.
It is an OO API that validates the Business Rules against single Domain Object. Domain Logic that involves Collection of Same Objects or Involve more than one Domain Objects goes to the Domain Services.
One of the problems with Domain Model (116) is the interface with relational databases.
In many ways this approach treats the relational database like a crazy aunt who's shut up in an attic and whom nobody wants to talk about. Means Object Relations Impedance Mismatch. OO API is hard to wrap around the RDBMS. As a result you often need considerable programmatic gymnastics to pull data in and out of the database, transforming between two different representations of the data. All the Hard Things of ORM are done by the ORM Frameworks.
One of the problems with Domain Model (116) is the interface with relational databases.
In many ways this approach treats the relational database like a crazy aunt who's shut up in an attic and whom nobody wants to talk about. Means Object Relations Impedance Mismatch. OO API is hard to wrap around the RDBMS. As a result you often need considerable programmatic gymnastics to pull data in and out of the database, transforming between two different representations of the data. All the Hard Things of ORM are done by the ORM Frameworks.
The short definition for the Domain Model Pattern is: “an object model of the domain that incorporates both behavior and data”.
The domain model is created in an application by introducing a whole layer of objects which model the business concepts and entities that the application is working in. It creates a set of interconnected objects for dealing with the logic required by the business environment. An object-oriented domain model will be quite like the database model it uses, but domain model not only contains the data and also the process need to be used with the data.
There are two common ways of using domain model. One is to model each database table (or logic tables based on application requirement) as one class. Other design patterns and inheritance can also be used here. Another way is to introduce rich domain model which is good for complex domain logic, and as the result, the model will not look like the data model anymore. The Active record pattern can be used as the data mapper if the domain logic is not very complex; in the case of very complex domain logic, the Data mapper pattern should be used to map between the application and the data.
The third pattern for representing domain logic in an application is the Domain Model. In this model the application is viewed as a set of interrelated objects. The core feature of these objects (referred to as Business Entities in Microsoft nomenclature) is that, unlike the Table Module approach, each object maps to an entity (not necessarily a database table) in the database. In other words, each primary object represents a single record in the database rather than a set of records and the object couples the object’s data with its behavior (business logic and data validation). Additional objects may represent calculations or other behavior. Ultimately, this approach requires at least the following:
To build an object used in a Domain Model a best practice is to follow the Layer SuperType pattern. Using this pattern an architect would develop a base class from which all domain objects would inherit as shown here:
You’ll notice that this abstract class contains the implementation of the Id property as well as the abstract Save and Delete methods and a protected field to determine if the object has been altered and is in need of removal. In addition, it shadows (implemented with the new keyword in C#) both signatures of the Equals method inherited from System.Object that is used to determine whether two instances of the object are equal. Note that these methods check the Id property but could alternately have been implemented to check against some other criterion or more likely overridden in the derived class and checked against other properties of the object. This class also uses the SerializableAttribute and XmlAttribute classes so that the object can be serialized to XML and its Id property represented as an attribute.
A derived Domain Model object, implemented by the Order class might then look as follows.
The key point to note about this class is that it combines data (the Quantity and ShipVia properties), behavior (the IsComplete, Save, CalcOrderTotal and other methods), and the relationships to other data (the Product and Customer properties that relate to the Product and Customer classes). The end result is a static structure diagram:
The second key point to note about this structure is that each object derived from BusinessObjectBase creates its own Id property in the object’s constructor and the Id property is represented as a Long (64-bit) integer. The strategy shown here is only one among several documented by Fowler as the Identity Field pattern. The considerations for Id generation are as follows:
Organizing Domain Logic: Domain Model
The third pattern for representing domain logic in an application is the Domain Model. In this model the application is viewed as a set of interrelated objects. The core feature of these objects (referred to as Business Entities in Microsoft nomenclature) is that, unlike the Table Module approach, each object maps to an entity (not necessarily a database table) in the database. In other words, each primary object represents a single record in the database rather than a set of records and the object couples the object’s data with its behavior (business logic and data validation). Additional objects may represent calculations or other behavior. Ultimately, this approach requires at least the following:
- Object-relational Mapping. Since this pattern does not rely on the DataSet object or even Typed DataSet objects, a layer of mapping code is required. At present the Framework does not contain built-in support for this layer. Look for support in the Microsoft Business Framework (MBF) technology to be released after the Whidbey release of VS .NET. Techniques to perform this mapping are covered in my article Software Design: Using data source architectural patterns in your .NET applications.
- ID Generation. Since each Domain Model object maps to an entity in the database, the objects need to store the database identity within the object (the CLR’s object system uniquely identifies each object based on its data). There are several techniques to do so documented by Fowler in his discussion of the Identity Field pattern.
- Strongly-Typed Collection Classes. Because objects in the Domain Model map intrinsically to an individual entity, representing multiple objects is handled through collections. Framework developers can therefore create strongly-typed collection classes to handle representing multiple domain objects. For more information see my article Take advantage of strongly typed collection classes in .NET.
To build an object used in a Domain Model a best practice is to follow the Layer SuperType pattern. Using this pattern an architect would develop a base class from which all domain objects would inherit as shown here:
<Serializable()> _ Public MustInherit Class BusinessObjectBase : Implements IComparable Protected _id As Integer ' could also use GUID or a key class <xml.serialization.xmlattribute()> _ Public Property Id() As Integer Get Return _id End Get Set(ByVal Value As Integer) _id = value End Set End Property MustOverride Function Save() As Boolean MustOverride Function Delete() As Boolean Public Shadows Function Equals(ByVal o As BusinessObjectBase) As Boolean If Me.Id = o.Id Then Return True Else Return False End If End Function Public Shared Shadows Function Equals(ByVal o As BusinessObjectBase, _ ByVal o1 As BusinessObjectBase) As Boolean If o.Id = o1.Id Then Return True Else Return False End If End Function Protected IsDirty As Boolean = False ' Used when the Sort method of the collection is called Public Function CompareTo(ByVal o As Object) As Integer _ Implements IComparable.CompareTo Dim b As BusinessObjectBase = CType(o, BusinessObjectBase) Return Me.Id.CompareTo(b.Id) End Function End Class
You’ll notice that this abstract class contains the implementation of the Id property as well as the abstract Save and Delete methods and a protected field to determine if the object has been altered and is in need of removal. In addition, it shadows (implemented with the new keyword in C#) both signatures of the Equals method inherited from System.Object that is used to determine whether two instances of the object are equal. Note that these methods check the Id property but could alternately have been implemented to check against some other criterion or more likely overridden in the derived class and checked against other properties of the object. This class also uses the SerializableAttribute and XmlAttribute classes so that the object can be serialized to XML and its Id property represented as an attribute.
A derived Domain Model object, implemented by the Order class might then look as follows.
<serializable> Public Class Order : Inherits BusinessObjectBase Private _orderId As Long Private _cust As Customer Private _prod As Product Private _quant As Integer = 1 'default Private _ship As ShipType = ShipType.Postal 'default Public Sub New() End Sub Public Sub New(ByVal cust As Customer, ByVal prod As Product) _InitClass(cust, prod, Nothing, Nothing End Sub Public Sub New(ByVal cust As Customer, _ ByVal prod As Product, ByVal quantity As Integer) _InitClass(cust, prod, quantity, Nothing) End Sub Public Sub New(ByVal cust As Customer, ByVal prod As Product, _ ByVal quantity As Integer, ByVal ship As ShipType) _InitClass(cust, prod, quantity, ship) End Sub Private Sub _InitClass(ByVal cust As Customer, _ ByVal prod As Product, ByVal quantity As Integer, _ ByVal ship As ShipType) _cust = cust _prod = prod Me.Quantity = quantity Me.ShipVia = ship Me.IsDirty = True ' Generate a new or temporary order id: use a system assigned key ' _orderId = key table GUID End Sub Public ReadOnly Property Customer() As Customer Get Return _cust End Get End Property Public ReadOnly Property Product() As Product Get Return _prod End Get End Property Public Property Quantity() As Integer Get Return _quant End Get Set(ByVal Value As Integer) If Value < 0 Then Throw New ArgumentOutOfRangeException( _ "Quantity must be greater than 0") End If _quant = Value Me.IsDirty = True End Set End Property Public Property ShipVia() As ShipType Get Return _ship End Get Set(ByVal Value As ShipType) _ship = Value Me.IsDirty = True End Set End Property Public Function CalcShippingCost() As Double ' calculate the shipping cost based on the Customer and Product objects ' store the shipping cost for this order End Function Public Function CalcOrderTotal() As Double ' calculate the total cost of the order with tax ' store the cost for this order End Function Public Function IsComplete() As Boolean ' Determines whether this order has enough information to save End Function Public Overrides Function Save() As Boolean ' Persist the order Me.IsDirty = False End Function Public Overrides Function Delete() As Boolean ' Remove the order End Function End Class
The key point to note about this class is that it combines data (the Quantity and ShipVia properties), behavior (the IsComplete, Save, CalcOrderTotal and other methods), and the relationships to other data (the Product and Customer properties that relate to the Product and Customer classes). The end result is a static structure diagram:
The second key point to note about this structure is that each object derived from BusinessObjectBase creates its own Id property in the object’s constructor and the Id property is represented as a Long (64-bit) integer. The strategy shown here is only one among several documented by Fowler as the Identity Field pattern. The considerations for Id generation are as follows:
- Use of system assigned keys. Here the assumption is made that the key value will be assigned by the system and not use a “natural key”. In practice this proves to be the more durable design since the independence of the keys allows them to remain fixed once assigned. This also disallows the use of compound keys (which if used should be implemented in a separate key class) which are difficult to manage and slow performance of the database.
- Use of data types. Here a 32-bit integer is used, however, unless uniqueness can be guaranteed in the generation of the ids it might be possible to duplicate keys which would cause problems once the object is persisted to the database. An alternative would include the use of System.GUID, which is (for all intents and purposes) guaranteed to be unique. If you wish to protect yourself against data type changes in the key you could also implement the key in a key class that abstracts the data within the key and performs any comparisons and generation.
- Generation of the ids. If a data type such as an integer is used, one technique for generating unique ids is to generate them from a key table. The downside of this technique is that it incurs a round trip to the database server.
- Uniqueness of the ids. In the code shown here it is assumed that each object generates its own key probably through the use of a key table. This then assumes that each object type (Order, Customer, Product) generates keys independently of the others. An alternate approach would be to create system wide unique ids through a key table, in which case the generation of the id could be placed in the base class. If the classes form an inheritance relationship, for example if the BookProduct class inherited from the Product class it would be assumed that the generation of the ids would take place in the Product class so that all of the objects generated by the inheritance hierarchy would be uniquely identified so that they could be stored in the same database table.
- Strong-typing. As the name implies, a custom collection can be strongly-typed, meaning that only objects of a specific type are allowed to be added to the collection.
- Custom Manipulation. A strongly-typed collection class also provides the opportunity to add custom behaviors to the class, for example, by providing custom sorting capabilities.
No comments:
Post a Comment