When writing object-oriented code, there are times when you need a different instance of the action object that you can introduce yourself according to different conditions. For example, a menu function can decide whether to use a horizontal or vertical arrangement based on the user's "skin" preferences, or a billing system can determine its own tax rate based on the user's delivery address.
Generally, an object instance of a control menu includes the Add (), delete (), and replace () menu elements, and is configured with the set () to manage the display mode with render (). Whatever menu you want to generate, you can use the same object class to handle it. The object instances of different menus are just different rules for the operation of the functions, at least in the example above the render () function is different.
But what if you need to increase the menu display mode, or do you need to determine the order of the menus according to the user's country, province, etc.? And if there are many ways in which functions are constantly changing, simple class encapsulation will become complex, difficult to understand, and upgraded.
Problem
How can you easily change the execution of an object instance, and therefore dynamically change the execution process while the code is executing? Once this functionality is implemented, if you write such a class definition to make maintenance and upgrades very simple?
Solutions
When a class encapsulates multiple operations, an object instance can dynamically select these operations, and a policy pattern can be used to differentiate the object itself from the operation rules. Alternatively, a simpler process is the way in which the functions defined in the class are controlled by a case statement. The simpler approach, of course, is to use the policy model.
The policy pattern is very powerful because the core idea of the design pattern itself is the idea of the polymorphism of object-oriented programming.
Outside the programming world, there are many examples of policy patterns. If I need to go to work in the morning from home, I can have a few strategies to consider: I can drive, take a bus, walk, car or even a helicopter ride. Each policy can get the same result, but they use different resources. The choice of strategy is based on cost, time, use of tools, and the convenience of each of these methods. A good strategy may not be used again the next day, so the choice of strategy is relative.
You have seen a similar example of a strategy pattern in the previous Factory model section: Because the cost of different features is different, the Monopoly game framework uses many similar attribute classes, but because the cost calculation is not derived from the class itself, So this cost calculation is relatively a templatemethod design pattern.
Example
For example, let's do a cache that stores PHP parameters. This CAHCE class needs to write variables to a file in PHP recognition, so you can load the file and use it later. This class should also allow you to add an identifier and a way to store each data.
Data caching
Note: Caching is used to cache resources in order to continue using them in the next operation. You can save time by creating and using caching to get data directly from the original database. The most common example of this is accessing a database or parsing a large XML document, or a large configuration file.
There is also a problem with caching: Your cache may lose synchronization with the original data. or the cache needs to use too much memory.
Initially, we developed a caching operation and did not use the policy pattern.
Because you may need to cache more than one value, you need to use identifiers to identify the elements you need to specify. In this example, the identifier is ' application_config '. Let's try an example of using cache.
PHP4
$config_cache =& new VarCache (‘application_config’);
if ($config_cache->isValid()) {
$config = $config_cache->get();
} else {
$config = slow_expensive_function_to_get_config();
$config_cache->set($config);
}
This code generates a new Varcache object that is stored in the $config_cache variable. The identifier for this data in the cache is ' Application_config '. If this data is in the cache, IsValid () returns True (true) and gets the data in the cache. Conversely, the value is retrieved and written to the cache for next use.
In accordance with the general requirements, let's start writing this code to test. First, if the data is not in the cache, the IsValid () method function should return a non-value (false).
class VarCacheTestCase extends UnitTestCase {
function TestUnsetValueIsInvalid() {
$cache =& new VarCache (‘foo’);
$this->assertFalse($cache->isValid());
}
Because Varcache now has no code, the easiest way is to construct a method function first.
class VarCache {
function isValid() {}
}
So that we can go on.
class VarCacheTestCase extends UnitTestCase {
function TestUnsetValueIsInvalid() { /* ... */ }
function TestIsValidTrueAfterSet() {
$cache =& new VarCache(‘foo’);
$cache->set (‘bar’);
$this->assertTrue($cache->isValid());
}
The test above verifies that the cached data is available.
Start writing the main part of the cache class. Varcache introduces an identifier, so constructor an object instance that should record it. There is also a set () method function that is used to cache data, or to modify the data in the cache when the data is present.
class VarCache {
var $_name;
function VarCache($name) {
$this->_name = ‘cache/’.$name;
}
function isValid() {
return file_exists ($this->_name.’.php’);
}
function set() {
$file_handle = fopen($this->_name.’.php’, ‘w’);
fclose($file_handle);
}
}