Difficulty |
2 |
Prerequisites |
|
In order to create a new pattern, we need to define a new subclass of Pattern2DImplementation
or Pattern3DImplementation
and define the at
method.
Next, we need to create a factory function that creates an instance of the new pattern implementation class and wraps it in a Pattern2D
or Pattern3D
.
#pragma once
#include "patterns/pattern.h"
namespace patterns
{
namespace _private_
{
class SomeNewPatternImplementation : public Pattern2DImplementation
{
public:
SomeNewPatternImplementation(parameters);
bool at(const math::Point2D& point) const override;
private:
// fields
};
}
Pattern2D factory_function(parameters);
}
#include "patterns/some-new-pattern.h"
patterns::_private_::SomeNewPatternImplementation::SomeNewPatternImplementation(parameters)
: m_fields(parameters)
{
// NOP
}
bool patterns::_private_::SomeNewPatternImplementation::at(const math::Point2D& point) const
{
/* pattern logic */
}
Pattern2D patterns::some_new_pattern(parameters)
{
return Pattern2D(std::make_shared<_private_::SomeNewPatternImplementation>(parameters));
}
This is a lot of boilerplate code to write.
The only part that distinguishes one pattern from another is at
's body.
Wouldn’t it make more sense to only have to define that part and let the rest be automatically generated for you?
Pattern2D patterns::some_new_pattern(parameters)
{
return generate_new_pattern(/* pattern logic */);
}
Making this possible is exactly the goal of this extension. This will save us from having to declare and define a class with fields and a constructor each time.
Create files |
1. 2D Implementation
As mentioned before, the one thing distinguishing one pattern from another is the pattern logic which normally resides within the at
method.
This logic is code, and code is typically contained within a function.
A lightweight syntax to define functions is to make use of lambdas, hence the name of this extension.
1.1. LambdaPattern2DImplementation
We will now define a class LambdaPattern2DImplementation
which takes care of most of the boilerplate.
Conceptually, it looks like this in pseudocode:
class LambdaPattern2DImplementation:
def __init__(self, func): # (1)
self.__func = func
def at(self, point2d):
return self.__func(point2d) # (2)
-
The constructor takes a function and stores it in a field.
-
The
at
method simply calls this function.
Define the
|
1.2. make_pattern
Next, we need a factory function which we’ll name make_pattern
.
It takes a function, creates a LambdaPattern2DImplementation
object with it and wraps it in a Pattern2D
object.
Define |
2. 3D Implementation
The 3D variant is nearly identical.
Create a class |
Overload |
3. Evaluation
Create a pattern named
|
Create a pattern named
|