Transaction Script: organizes business logic by procedures where each procedure handles a single request for the presentation
- Domain logic primarily organized by the transactions that you carry out with the system
- You can either have several transaction scripts in one class, or each in its own class (using the Command pattern: a command object encapsulates an action and its parameters)
Domain Model: an object model of the domain that incorporates both behavior and data
- A simple domain model looks very much like the database design with mostly one domain object for each DB table
Table Module: a single instance that handles the business logic for all rows in a database table or view
It organizes domain logic with one class per table in the database, and a single instance of a class contains the various procedures that will act on data
The primary distinction with “Domain Model” is that, if you have many orders, a “Domain Model” will have one order object per order while a “Table Module” will have one object to handle all orders
Table Module has no notion of an identity for the objects it’s working with
Table Module may include queries as factory methods. The alternative is a “Table Data Gateway”
Service Layer: defines an application’s boundary with a layer of services that establishes a set of available operations and coordinates the application’s response in each operation
A service layer defines an application’s boundary and its set of available operations from the perspective of interfacing client layers
You need it in applications with more than one kind of client of its business logic.
MAPPING TO RELATIONAL DATABASES
Gateway: an object that encapsulates access to an external system or resource
Row Data Gateway: an object that acts as a Gateway to a single record in a data source. There is one instance per row
- You have an instance for each row that’s returned by a query
- You face the issue of where to put the find operations. It often makes sense to have separate finder objects
- It’s sometimes difficult to tell the difference between a “Row Data Gateway” and an “Active Record” => if there’s any domain logic present, then it’s an “Active Record”
- Most often used with “Transaction Script”
Table Data Gateway: an object that acts as a Gateway to a database table. One instance handles all the rows in the table
- Single object for each table in the DB => if you use recordset
- Goes very well with table module
(Record Set: “A recordset is a data structure that consists of a group of database records, and can either come from a base table or as the result of a query to the table.”)
Active Record: an object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data
It can have static find methods.
Any business logic sits directly in it.
Data Mapper: A layer of mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself
- Makes your indirection layer entirely responsible for the mapping between domain objects and database tables
- It uses “Identity Map” to see if a class is already loaded.
---
Summary: Gateway not recommended. If domain logic is simple and there’s a close correspondence between classes and tables =>Active Record. Something more complicated > Data Mapper.
---
OBJECT-RELATIONAL BEHAVIORAL PATTERNS
As you read objects and modify them, you have to ensure that the DB state you are working with stays consistent. If you read some objects, it’s important to ensure that the reading is isolated so that no other process changes any of the objects you’ve read while you are working on them.
Unit of Work: maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems
As soon as you start doing something that may affect a database, you create a Unit of Work to keep track of changes.
Keeps track of all objects read form the database, together will all objects modified in any way. It also handles how updates are made to the DB. Instead of the app programmer invoking explicit save methods, the programmer tells the unit of work to commit. The unit of work is like a controller of the database mapping.
A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you’re done, it figures out everything hat needs to be done to alter the database as a result of your work.
- With caller registration, the user of an object has to remember to register the object with the Unit of work for changes
- With object registration, loading an object form the database registers the object as clean; the setting methods register the object as dirty. (The usual trick here is to place registration methods in object methods)
- With a unit of work controller, rather than marking objects as dirty, the Unit of Work takes a copy at read time and then compares the object at commit time
Identity Map: ensures that each object gets loaded only once by keeping every loaded object in a map. Looks up objects using the map when referring to them
In a simple case, with an isomorphic schema, you’ll have one map per DB table.
You need to ensure that each session gets its own instance that’s isolated from any other session instance. Thus you need to put the identity map on a session-specific object.
Lazy Load: an object that doesn’t contain all of the data you need but knows how to get it
For loading data form a DB into memory it’s handy to design things so that as you load an object of interest you also load the objects that are related to it. However, loading one object can have the effect of loading a huge number of related objects. A Lazy Load interrupts this loading process, leaving a marker in the object structure so that if the data is needed it can be loaded only when it is used.
- Lazy initialization: every access to the field checks first to see if it’s null. If so, it calculates the value of the field before returning the field. (No good if null is a valid value for that field)
- Virtual proxy: it’s an object that looks like the object that should be in the field, but doesn’t actually contain anything. Only when one of its methods is called does it load the correct object from the DB
- Value holder: object that wraps some other object. To get the underlying object you ask the value holder for its value, but only on the first access does it pull the data from the DB
- Ghost: is the real object in a partial state. When you load the object from the DB it contains just its ID. Whenever you try to access a field it loads its full state
===============
Dependency Injection (DI) in computer programming refers to the process of supplying an external dependency to a software component. It is a specific form of inversion of control where the concern being inverted is the process of obtaining the needed dependency.
When the dependency injection technique is used to decouple high-level modules from low-level services, the resulting design guideline is called the Dependency inversion principle.
Dependency lookup: We avoid hard-coding the names of classes on which we depend into our code because static binding severely limits our options for how the software is configured as it runs. Instead, we hard-code that name of a "component broker" that returns to us a ready to use object. The component broker provides some means for the client software or perhaps a system configuration manager to tell the SUT in question what objects to use for each component request.
No comments:
Post a Comment