In the process of forming an application software, some unexpected business logic appears everywhere. For example, based on price considerations, the task must reduce the project, and that task must choose the right ratio because of the sales tax, while other tasks must be terminated because of other special conditions. Some business rules are simple and require less than one or two Boolean comparisons, but their rules may require time-consuming estimates that require querying the database or user input data to boot.
You can translate abstractions (such as a business rule) into something tangible by writing code. But abstractions (such as shopping, tax rates, or computing sea freight, for example) have their evolutionary way, and these changes can easily baffle a less fortunate developer. In order to be safe and reliable--what you've seen so far in this book--it's a perfect idea to isolate and encapsulate as much of the easy-changing modules as possible. And it does have a sensible strategy for dealing with business rules.
Problem description
Is there a clear way to encapsulate business logic? Is there a technology that is easy to rewrite and reuse?
Solution
Canonical patterns are developed for validation and selection:
Confirm whether a particular object satisfies a certain standard
Select from the collection the elements that meet the given criteria.
Canonical mode allows you to effectively organize these standards and use them flexibly in your applications.
The code refactoring technology has inspired your interest, and you've decided to use it to improve the clarity and reusability of your code. The canonical pattern further deepens this step through systematization, which decomposes the structure into separate objects that can be conveniently plugged into the appropriate place for your application. In many cases, the specification objects are parameterized in your application and are often grouped together to construct complex, logical expressions.
Related knowledge
Eric Evans and Martin Fowler published an article on the canonical model, the address is: http://www.martinfowler.com/apsupp/spec.pdf
This pattern is detailed on page No. 224 to No. 273 of the Eric Evans book, "Dynamic Drive Design" ("Domain driven Designs").
In order to fully cover this pattern, this chapter is organized into logical three parts. The first part is a pure example to illustrate the basic concept of schema. (Evans and Fowler refer to this as "hard-coded Code hard Coded specification"). The next section shows how to build a parameterized canonical model that provides a more dynamic and flexible framework for reusing canonical patterns (or, hence, "parameterized specifications"). In the last installment, we developed a "solution factory" (Policy Factory), which centralizes a number of spec objects into an Easy-to-use package (package).
Traveling to Warm destinations (travel to a warm destination)
Recently, my family and I plan to go on a holiday, my wife wants to go to a "warm place". Although there are countless travel-related sites, none of the sites we visited have the ability to provide detailed weather information for each destination. No way, we have to go to the weather.com and then start the search, which is very inconvenient. Now let's change the situation and add a weather search function for a hypothetical travel site. Here we use the canonical Pattern Guide to guide you through the code to compare the minimum temperatures expected by travelers and the average temperature of many destinations
First, we create some very simple objects. The first is the Traveler (a traveler), which stores the preferred minimum temperature.
// PHP5
class Traveler {
public $min_temp;
}
Next we create an object to represent the destination (destination). Since the average temperature is a key criterion, the destination construction function (__constructor) should be given a 12-D array, each of which corresponds to the average temperature per month of the year.
class Destination {
protected $avg_temps;
public function __construct($avg_temps) {
$this->avg_temps = $avg_temps;
}
}
The destination (destination) also has a method by which the average temperature of the destination in a specified month can be obtained by invoking this method.
class Destination {
//...
public function getAvgTemPByMonth($month) {
$key = (int)$month - 1;
if (array_key_exists($key, $this->avg_temps)) {
return $this->avg_temps [$key];
}
}
}
Finally, a journey (class trip) is made up of a traveler (class traveler), a destination (class destination) and a date (a date).
class Trip {
public $date;
public $traveler;
public $destination;
}
Given these objects, you can get the month of travel through trip::date, and you can compare the average monthly temperature of the destination with the minimum desired temperature of the traveller. (This comparison may not be particularly complicated, but you still need to do it yourself)
Let's look at how to implement the business logic of "warm destinations" in canonical mode, and see how to apply this pattern to validate each destination and select all the right destinations.
Sample code
The core of the canonical pattern is an object with the IsSatisfiedBy () method, and the IsSatisfiedBy () method receives a variable to evaluate and return a Boolean value based on the canonical standard.
"The destination is warm enough" may be the standard:
class TripRequiredTemperatureSpecification {
public function isSatisfiedBy($trip) {
$trip_temp = $trip->destination->getAvgTemPByMonth(
date(‘m’, $trip->date));
return ($trip_temp >= $trip->traveler ->min_temp);
}
}