By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,784 Members | 3,274 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,784 IT Pros & Developers. It's quick & easy.

Require help learning how to decompose class into policies

P: n/a
Below is a class that is suppose to represent a segment of memory or a
contents of a binary image (e.g. ELF executable). I have started to read
Modern C++ Design and thought the best way to ensure I was understanding
the chapter on policy classes was to attempt to apply them to my project.
I understand the general concept of policies but I lack the knowledge and
wisdom of how to identify them in an existing project. So I figured to get
an existing class and start from there.

Some notes about the code:

- Tracing: The following statement is only activate if the ./configure
script was run with --enable-debug. Otherwise its compiled out by
the compiler. If debugging is enabled AND the trace level of the
library was set to TraceLevel::DETAIL or higher then the message
will appear.

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Entering Memory_Map::swap" );

- Assert: The following statement will perform either a throw an exception
which performs a typical abort after finding a false expression,
reporting where in the code the assert happened along with a descriptive message.
Otherwise a developer can provide another exception which can take a different
approach to terminating the program.

Assert::bool_check ( size != 0, "Size of memory map is zero." );

My first thoughts where to make the Asserts into a policy. Second place could be the to_String
function. One way of printing could be a indented string with spaces or another method writing the content
of the class as a XML string. Any help is appreciated.

Stephen

----------------------
HEADER
----------------------

#ifndef MEMORY_MAP_H_
#define MEMORY_MAP_H_

#include <boost/shared_ptr.hpp>
#include <iostream>
#include <iomanip>
#include <vector>
#include <map>
#include <boost/enable_shared_from_this.hpp>
#include "Data_Types.h"

namespace libreverse { namespace data_container {

class Memory_Map : public boost::enable_shared_from_this<Memory_Map>
{
public:

/**
* \brief Set up a blank memory map of a set size
*
* \param size Size of memory map to allocate
*
* \param base_address The memory address of the first byte
*
* \pre size has a value of 0 or more
*
* \pre base_address has a value of 0 or more
*
* \post Size of memory map has been set to the value of the
* input variable 'size'
*
* \post Base addres of the memory map has been set to the
* value of the input variable 'base_address' or the default
* value of zero
*/
explicit Memory_Map ( boost::uint32_t size,
boost::uint32_t base_address = 0 );

/**
* \brief Set up a memory map of a set size with the contents
* of the input file stream.
*
* \param input_ref Input file stream where data is stored.
*
* \param base_address The memory address of the first byte
*
* \pre size has a value of 0 or more
*
* \pre base_address has a value of 0 or more
*
* \post Size of memory map has been set to the value of the
* size of the input file stream.
*
* \post Base addres of the memory map has been set to the
* value of the input variable 'base_address' or the default
* value of zero
*/
explicit Memory_Map ( std::ifstream& input_ref,
boost::uint32_t base_address = 0 );

/**
* \brief Copy constructor
*
* \pre The input reference is a fully initialized Memory_Map
*
* \post The output Memory_Map is a deep copy of the input
*/
explicit Memory_Map ( Memory_Map const& rhs );

virtual ~Memory_Map();

/**
* \brief assignment operator
*
* This function handles copying the rhs reference even if the rhs
* is a reference to this object.
*
* \pre The input reference is a fully initialized Memory_Map
*
* \post The output Memory_Map is a deep copy of the input
*/
Memory_Map& operator= ( Memory_Map const& rhs );

/**
* \brief assignment operator
*
* \pre The input reference is a fully initialized Memory_Map
*
* \post The output Memory_Map is a deep copy of the input
*/
void swap ( Memory_Map& rhs );

/**
* \brief Adjust the pointer into the memory to the location
* specified in by the address.
*
* \post The present position is set to the new location.
*/
boost::int8_t address_Seek ( boost::uint32_t address );

/**
* \brief Adjust the pointer into the memory to the location
* specified in by the index.
*
* \post The present position is set to the new location.
*/
template <typename Offset_Type>
boost::int8_t
index_Seek ( Offset_Type offset )
{
if ( offset m_data.size() - 1 )
{
std::cerr << "The offset given, " << offset
<< " is invalid. Its pointing to a "
<< std::endl
<< "memory location outside of space "
<< "allocated to"
<< std::endl
<< "this Memory Map. ("
<< m_data.size() << ")"
<< std::endl;

return data_types::Memory_Map::OUT_OF_RANGE;
}

m_present_pos = offset;

return data_types::Memory_Map::SUCCESS;
}

/**
* \brief Read 'length' units of data from this Memory Map.
*
* The read data will be placed into the destination startin
* at the beginning.
*
* \pre The destination pointer is initialized.
*
* \pre Read length is non-zero
*
* \post The present position is set to the new location.
*/
boost::int8_t read ( data_types::Memory_Map::pointer_t dest_addr_ptr,
boost::uint32_t length );

/**
* \brief This copies from the src_ptr to the local Memory
* Map. It is assumed that the local Memory Map has been
* adjusted to the position where data will be store. It is
* also assumed that the src_ptr has been adjusted to the
* position where we will start reading data.
*
* \pre The destination pointer is initialized.
*
* \pre Read length is non-zero
*
* \post The present position is set to the new location.
*/
boost::int8_t copy ( data_types::Memory_Map::ptr_t src_ptr,
boost::uint32_t length );

/**
* \brief This produces a new Memory Map containing a subset
* of the parent map. It is assumed that the parent Memory Map
* has been adjusted to the position where we will start
* reading data.
*
* \pre Present Position of the pointer into the data will not
* go past the boundary with the given length.
*
* \pre Length is non-zero
*/
std::pair <data_types::Memory_Map::ptr_t, boost::int8_t>
subset ( boost::uint32_t length );

data_types::Memory_Map::iterator begin();

data_types::Memory_Map::const_iterator begin() const;

data_types::Memory_Map::const_iterator end() const;

boost::uint32_t get_Present_Position_Value (void) const;

data_types::Memory_Map::const_iterator get_Present_Position (void) const;

boost::uint32_t get_Present_Position_Address (void) const;

boost::uint32_t get_Previous_Position_Value (void) const;

data_types::Memory_Map::const_iterator get_Previous_Position (void) const;

boost::uint32_t get_Previous_Position_Address (void) const;

boost::uint32_t const size (void) const;

std::string to_String (void) const;

bool operator== ( Memory_Map& rhs_ref ) const;

bool allocate_Range ( boost::uint32_t address, boost::uint32_t size );

private:

Memory_Map();

data_types::Memory_Map::Values_t m_data;

boost::uint32_t m_present_pos; // Present index

boost::uint32_t m_previous_pos; // Previous index

boost::uint32_t m_base_address;

};

} /* namespace data_types */
} /* namespace libreverse */

#endif /* MEMORY_MAP_H_ */

--------------------
SOURCE
---------------------
#include "Memory_Map.h"
#include <sstream>
#include <fstream>
#include <boost/format.hpp>
#include "libreverse/Trace.h"
#include "libreverse/Assert.h"

using namespace libreverse::api;
using namespace libreverse::assert;
using namespace libreverse::trace;

namespace libreverse { namespace data_container {

template < template<classclass CheckingPolicy >
Memory_Map::Memory_Map ()
: m_data (),
m_present_pos ( 0 ),
m_previous_pos ( 0 ),
m_base_address ( 0 )
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Inside Memory_Map constructor" );
}

Memory_Map::Memory_Map ( boost::uint32_t size,
boost::uint32_t base_address )
: m_data ( size, 0 ),
m_present_pos ( 0 ),
m_previous_pos ( 0 ),
m_base_address ( base_address )
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Entering Memory_Map constructor (uint32,uint32)" );

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DATA,
boost::str ( boost::format ( "paramaters: size = 0x%1X base address = 0x%2X")
% size
% base_address ) );
Assert::bool_check ( size != 0, "Size of memory map is zero." );

Assert::bool_check ( ( m_data.size() == size ), "Size of the image data array is not equal to the requested size." );
Assert::bool_check ( ( m_base_address == base_address ), "Base address of image is not equal to the requested address.");

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Exiting Memory_Map constructor (uint32,uint32)" );
}

Memory_Map::Memory_Map ( std::ifstream& input_ref,
boost::uint32_t base_address )
: m_present_pos ( 0 ),
m_previous_pos ( 0 ),
m_base_address ( base_address )
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Entering Memory_Map constructor (ifstream,uint32)" );

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DATA,
boost::str ( boost::format ( "paramaters: ifstream = 0x%1X base address = 0x%2X")
% &input_ref
% base_address ) );
Assert::bool_check ( input_ref.good(), "Input file stream is not ready for I/O operations." );

char byte = 0;

while ( !input_ref.eof() )
{
input_ref.read ( &byte, sizeof(byte) );
m_data.push_back ( byte );

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DATA,
boost::str ( boost::format (" byte: 0x%1X" )
% static_cast<boost::uint16_t>(byte) ) );

}

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DATA,
boost::str ( boost::format (" data size: 0x%1d" ) % m_data.size() ) );

input_ref.clear();
input_ref.seekg ( std::ios_base::beg );

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Exiting Memory_Map constructor (ifstream,uint32)" );
}

Memory_Map::Memory_Map ( Memory_Map const& rhs )
: boost::enable_shared_from_this<Memory_Map>(rhs),
m_data ( rhs.m_data.size() ),
m_present_pos ( rhs.m_present_pos ),
m_previous_pos ( rhs.m_previous_pos )
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Entering Memory_Map copy constructor" );

std::copy ( rhs.m_data.begin(),
rhs.m_data.end(),
m_data.begin() );

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Exiting Memory_Map copy constructor" );

}

Memory_Map::~Memory_Map ()
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Memory_Map destructor called" );
}

boost::int8_t
Memory_Map::read ( data_types::Memory_Map::pointer_t dest_addr_ptr,
boost::uint32_t length )
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Entering Memory_Map::read" );

assert ( dest_addr_ptr != 0 );
assert ( length != 0 );

if ( m_present_pos + length m_data.size() )
{
Trace::write_Trace
( TraceArea::DATA_CONTAINERS,
TraceLevel::ERROR,
boost::str(boost::format("Present Position: %d") %
m_present_pos) );

Trace::write_Trace
( TraceArea::DATA_CONTAINERS,
TraceLevel::ERROR,
boost::str(boost::format("Input read length: %d") %
length) );

Trace::write_Trace
( TraceArea::DATA_CONTAINERS,
TraceLevel::ERROR,
boost::str(boost::format("Data size: %d") %
m_data.size()) );

Trace::write_Trace
( TraceArea::DATA_CONTAINERS,
TraceLevel::ERROR,
boost::str(boost::format("The resulting pointer is invalid. %d + %d %d")
% m_present_pos
% length
% m_data.size() ) );

Trace::write_Trace
( TraceArea::DATA_CONTAINERS,
TraceLevel::ERROR,
"Its pointing to a memory location out side of space allocated to this Memory Map.");

return data_types::Memory_Map::INVALID_INDEX;
}

data_types::Memory_Map::Values_t::const_iterator pos = m_data.begin();

std::copy ( pos + m_present_pos,
pos + m_present_pos + length,
dest_addr_ptr );

m_previous_pos = m_present_pos;
m_present_pos += length;

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Exiting Memory_Map::read" );

return data_types::Memory_Map::SUCCESS;
}

data_types::Memory_Map::iterator
Memory_Map::begin()
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Inside Memory_Map::begin" );
return m_data.begin();
}

data_types::Memory_Map::const_iterator
Memory_Map::begin() const
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Inside Memory_Map::begin (const)" );

return m_data.begin();
}

data_types::Memory_Map::const_iterator
Memory_Map::end() const
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Inside Memory_Map::end (const)" );

return m_data.end();
}

boost::uint32_t
Memory_Map::get_Present_Position_Value (void) const
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Inside Memory_Map::get_Present_Position_Value" );

return m_present_pos;
}

data_types::Memory_Map::const_iterator
Memory_Map::get_Present_Position (void) const
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Inside Memory_Map::get_Present_Position" );

return m_data.begin() + m_present_pos;
}

boost::uint32_t
Memory_Map::get_Present_Position_Address (void) const
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Inside Memory_Map::get_Present_Position_Address" );

boost::uint32_t position_address = m_base_address + m_present_pos;

return position_address;
}

boost::uint32_t
Memory_Map::get_Previous_Position_Value (void) const
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Inside Memory_Map::get_Previous_Position_Value" );

return m_previous_pos;
}

data_types::Memory_Map::const_iterator
Memory_Map::get_Previous_Position (void) const
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Inside Memory_Map::get_Previous_Position" );

return m_data.begin() + m_previous_pos;
}

boost::uint32_t
Memory_Map::get_Previous_Position_Address (void) const
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Inside Memory_Map::get_Previous_Position_Address" );

boost::uint32_t position_address = m_base_address + m_previous_pos;

return position_address;
}

boost::uint32_t const
Memory_Map::size (void) const
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Inside Memory_Map::size" );

return m_data.size();
}

boost::int8_t
Memory_Map::copy ( data_types::Memory_Map::ptr_t src_ptr,
boost::uint32_t length )
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Entering Memory_Map::copy" );

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DATA,
boost::str ( boost::format ("parameters: src_ptr address = 0x%1p length=0x%2X (%3d)" )
% src_ptr.get()
% length
% length ) );

assert ( src_ptr.get() != 0 );
assert ( length != 0 );

// Off the end check
if ( m_present_pos + length m_data.size() )
{
Trace::write_Trace
( TraceArea::DATA_CONTAINERS,
TraceLevel::ERROR,
boost::str(boost::format("The present position
pointer will be invalid if we write from the present\nposition with the
given length. It will cause an segfault. Recheck the value\ngiven for
length (%d) or check the setting of the present position.")
% length ) );

return data_types::Memory_Map::OUT_OF_RANGE;
}

std::copy ( src_ptr->get_Present_Position(),
src_ptr->get_Present_Position() + length,
m_data.begin() + m_present_pos );

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Exiting Memory_Map::copy" );

return data_types::Memory_Map::SUCCESS;
}

std::pair<data_types::Memory_Map::ptr_t, boost::int8_t>
Memory_Map::subset ( boost::uint32_t length )
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Entering Memory_Map::subset" );

assert ( length != 0 );

data_types::Memory_Map::ptr_t result_ptr
( new Memory_Map ( length,
this->get_Present_Position_Address() ) );

/*
* There is something wrong with the m_data. Its
*/
boost::int8_t result =
result_ptr->copy ( this->shared_from_this(), length );

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Exiting Memory_Map::subset" );

return std::make_pair ( result_ptr , result );
}

std::string
Memory_Map::to_String (void) const
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Entering Memory_Map::to_String" );

std::stringstream output;
std::stringstream char_output;

output << "----------------------------------------" << std::endl;

boost::uint8_t byte_counter = 0;

for ( boost::uint32_t index = 0;
index < m_data.size();
++index )
{
if ( byte_counter == 0 )
{
output << boost::format("%1X: ") % ( m_base_address + index );
}

output << boost::format("%1X") %
boost::io::group ( std::hex,
std::setw(2),
std::setfill('0'),
static_cast<boost::uint16_t>(m_data[index]));

if ( ( m_data[index] 0x1F ) &&
( m_data[index] < 0x7F ) )
{
char_output << boost::format("%1c") % m_data[index];
}
else
{
char_output << ".";
}

if ( ( byte_counter == 3 ) ||
( byte_counter == 7 ) ||
( byte_counter == 11 ) )
{
output << " ";
byte_counter++;
}
else if ( byte_counter != 15 )
{
output << " ";
byte_counter++;
}
else
{
byte_counter = 0;
output << " " << char_output.str();
char_output.str("");
output << std::endl;
}
}

if ( byte_counter != 15 )
{
for ( ;
byte_counter <= 15;
byte_counter++ )
{

output << " ";
char_output << ".";

if ( ( byte_counter == 3 ) ||
( byte_counter == 7 ) ||
( byte_counter == 11 ) )
{
output << " ";
}
else if ( byte_counter != 15 )
{
output << " ";
}
else
{
output << " " << char_output.str();
output << std::endl;
}
}
}

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Exiting Memory_Map::to_String" );

return output.str();
}

bool
Memory_Map::operator== ( Memory_Map& rhs_ref ) const
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Inside Memory_Map::operator== (equality)" );

return ( m_data == rhs_ref.m_data );
}

boost::int8_t
Memory_Map::address_Seek ( boost::uint32_t address )
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Entering Memory_Map::address_Seek" );

// If index is outside the range of the map
if ( ( address < m_base_address ) ||
( address m_base_address + m_data.size() ) )
{
std::cerr << "The address given, "
<< boost::format("%1X") % address
<< " is invalid. Its pointing to a "
<< std::endl
<< "memory location outside of space "
<< "allocated to"
<< std::endl
<< "this Memory Map. (";

std::cerr << boost::format("%1X") % m_base_address << " - ";

std::cerr << boost::format("%1X") % ( m_base_address + m_data.size() ) << ")"
<< std::endl;

return data_types::Memory_Map::OUT_OF_RANGE;
}

m_previous_pos = m_present_pos;
m_present_pos = address - m_base_address;

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Exiting Memory_Map::address_Seek" );

return data_types::Memory_Map::SUCCESS;
}

Memory_Map&
Memory_Map::operator= ( Memory_Map const& rhs )
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Entering Memory_Map::operator= (assignment)" );
Memory_Map temp ( rhs );
swap ( temp );

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Exiting Memory_Map::operator= (assignment)" );

return *this;
}

void
Memory_Map::swap ( Memory_Map& rhs )
{
Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Entering Memory_Map::swap" );

std::swap ( m_data, rhs.m_data );

Trace::write_Trace ( TraceArea::DATA_CONTAINERS,
TraceLevel::DETAIL,
"Exiting Memory_Map::swap" );

}

} /* Namespace data_types */
} /* namespace libreverse */

Sep 5 '07 #1
Share this Question
Share on Google+
3 Replies


P: n/a
On Sep 6, 12:49 am, Stephen Torri <sto...@torri.orgwrote:
Below is a class that is suppose to represent a segment of memory or a
contents of a binary image (e.g. ELF executable). I have started to read
Modern C++ Design and thought the best way to ensure I was understanding
the chapter on policy classes was to attempt to apply them to my project.
I understand the general concept of policies but I lack the knowledge and
wisdom of how to identify them in an existing project. So I figured to get
an existing class and start from there.
This sounds slightly backwards to me. Policies are a tool: a
means, and not a goal. If you don't feel the need for them (and
most application software won't), then all they do is add
unnecessary complexity. It's only when you end up with several
classes which differ only in a few specific operations that you
should start thinking about some sort of generic solution: the
template method pattern, policies, or whatever.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Sep 6 '07 #2

P: n/a
On Thu, 06 Sep 2007 08:35:23 +0000, James Kanze wrote:
This sounds slightly backwards to me. Policies are a tool: a means, and
not a goal. If you don't feel the need for them (and most application
software won't), then all they do is add unnecessary complexity. It's
only when you end up with several classes which differ only in a few
specific operations that you should start thinking about some sort of
generic solution: the template method pattern, policies, or whatever.
I do not know if I need policies or not. I see the strength in using them but
what I do not gather from Alexandrescu's book is when I should use them. He
gives the advice that

"When you decompose a class in policies, it is very important to find an
orthogonal decomposition. An orthogonal decomposition yields policies that
are completely independent of each other. You can easily spot a nonorthogonal
decomposition when various policies need to know about each other."

I first do not understand what the word orthogonal decomposition means here.
I do not understand how to think about this advice.
Sep 6 '07 #3

P: n/a
On Sep 6, 3:43 pm, Stephen Torri <sto...@torri.orgwrote:
On Thu, 06 Sep 2007 08:35:23 +0000, James Kanze wrote:
This sounds slightly backwards to me. Policies are a tool: a means, and
not a goal. If you don't feel the need for them (and most application
software won't), then all they do is add unnecessary complexity. It's
only when you end up with several classes which differ only in a few
specific operations that you should start thinking about some sort of
generic solution: the template method pattern, policies, or whatever.
I do not know if I need policies or not.
You almost never need policies unless you are writing very low
level library code, and not that often then. With a very few
notable exceptions, policies are a solution in search of a
problem.
I see the strength in
using them but what I do not gather from Alexandrescu's book
is when I should use them.
The answer is: almost never.
He gives the advice that
"When you decompose a class in policies, it is very important
to find an orthogonal decomposition. An orthogonal
decomposition yields policies that are completely independent
of each other. You can easily spot a nonorthogonal
decomposition when various policies need to know about each
other."
I first do not understand what the word orthogonal
decomposition means here.
It's exactly what he says in the second sentence: orthogonal
decomposition means that the separate parts are independant, and
don't need to know about any of the other parts. This is
important anytime you start decomposing: policies, mixins, or at
a higher level, subsystems. With regards to policies: if the
need for policies is not very frequent, the need for a single
component to have several different policies is even rarer (and
orthogonal decomposition only enters into account in those
cases).

If you're familiar with OO technology and design patterns:
policies are basically the equivalent of the template method
pattern or the strategy pattern (both of which are generally
preferable to policies anywhere but at the lowest level); using
multiple policies on a single component is basically the same as
mixins. And the use of the first two patterns if far more
prevalent than the use of mixins (to the point that some
so-called OO languages don't even allow mixins).

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Sep 7 '07 #4

This discussion thread is closed

Replies have been disabled for this discussion.