简体   繁体   中英

Understanding the strategy pattern

I have looked all over the web for good examples of the strategy pattern, but the examples I find are way to simplified.

I want to implement MyMatrix class. for this, I'm using the strategy pattern, ie I created a Matrix class, and two inheriting classes: RegMatrix and SparseMatrix which differ in implementation.

I know MyMatrix should hold a pointer to Matrix (let's call it *_matrix), and then if for example I want to implement the function "print" of MyMatrix, I should do: _matrix->print() and then it chooses the appropriate implementation.

only thing I don't understand is this: In the constructor of MyMatrix, which gets an array, and matrix sizes, do I need to choose a certain object of type Matrix and initialize it? I mean, should I do this:

MyMatrix::MyMatrix(double arr[], unsigned int colSize, unsigned int rowSize)
{
    _colSize = colSize;
    _rowSize = rowSize;
    _matrix = new RegMatrix(arr, colSize, rowSize);
}

The common variant is to pass an instance of the interface (Matrix) to the constructor.

MyMatrix::MyMatrix(const Matrix& behaviour):
  colSize(behaviour.getCols()), rowSize(behaviour.getRows()), matrix(behaviour)
{
}

// creation
MyMatrix m(SparseMatrix(4, 2, arr));

Use initializers. Don't use superfluous underscores. See Alf's comment. The colSize and rowSize are likely not needed, as they are duplicated in the Matrix implementation.

In C++ std::function can be regarded as a generic implementation of the strategy pattern. The word “pattern” implies that there can be no concrete general implementation, but it's not difficult to deal with that contradiction. Eg by simply ignoring it.


An in my opinion good example of the strategy pattern in C++ is a general cleanup facility, a scope guard . In C++03 implementing a scope guard involved dealing with the internal aspects of the strategy pattern such as pointer to implementation, and Petru Marginean invented an ingenious way to leverage the lifetime extension of temporary bound to reference, for this. In C++11 a scope guard class is trivially expressed in terms of std::function :

class Scope_guard
{
private:
    function<void()> cleanup_;

    Scope_guard( Scope_guard const& ) = delete;
    Scope_guard& operator=( Scope_guard const& ) = delete;

public:
    void dismiss() { cleanup_ = []{}; }

    ~Scope_guard() { cleanup_(); }

    Scope_guard( function<void()> const& cleanup )
        : cleanup_( cleanup )
    {}
};

and used like

void foo()
{
    Handle const       h = createThingy();
    Scope_guard const  h_cleanup( [=]{ destroyThingy( h ); } );

    // Using h here.
}

in order to use a C style interface directly, with C++ style coding.

Disclaimer 1: code untouched by compiler's hands.

Disclaimer 2: although this shares the implementation aspect with the strategy pattern, the matter of whether simple cleanup, ie a single action, is an “algorithm” is not entirely clear.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM