How to smooth a bold interface without breaking the Decorator pattern?

In my C ++ library code, I use an abstract base class as an interface to all the various types of objects that are capable of input / output. Currently, it looks like this:

// All-purpose interface for any kind of object that can do I/O
class IDataIO
{
public:
   // basic I/O calls
   virtual ssize_t Read(void * buffer, size_t size) = 0;
   virtual ssize_t Write(const void * buffer, size_t size) = 0;

   // Seeking calls (implemented to return error codes
   // for I/O objects that can't actually seek)
   virtual result_t Seek(ssize_t offset, int whence) = 0;
   virtual ssize_t GetCurrentSeekPosition() const = 0;
   virtual ssize_t GetStreamLength() const = 0;

   // Packet-specific calls (implemented to do nothing
   // for I/O objects that aren't packet-oriented)
   virtual const IPAddressAndPort & GetSourceOfLastReadPacket() const = 0;
   virtual result_t SetPacketSendDestination(const IPAddressAndPort & iap) = 0;
};

This works very well - I have various specific subclasses for TCP, UDP, files, memory buffers, SSL, RS232, stdin / stdout, etc., and I can write agnostic I / O procedures that can be used in combination with any of them.

decorator, IDataIO , . , / IDataIO. ():

/** Example decorator class:  This object wraps any given
  * child IDataIO object, such that all data going out is
  * obfuscated by applying an XOR transformation to the bytes,
  * and any data coming in is de-obfuscated the same way.
  */
class XorDataIO : public IDataIO
{
public:
   XorDataIO(IDataIO * child) : _child(child) {/* empty */}
   virtual ~XorDataIO() {delete _child;}

   virtual ssize_t Read(void * buffer, size_t size)
   {
      ssize_t ret = _child->Read(buffer, size);
      if (ret > 0) XorData(buffer, ret);
      return ret;
   }

   virtual ssize_t Write(const void * buffer, size_t size)
   {
      XorData(buffer, size);   // const-violation here, but you get the idea
      return _child->Write(buffer, size);
   }

   virtual result_t Seek(ssize_t offset, int whence) {return _child->Seek(offset, whence);}
   virtual ssize_t GetCurrentSeekPosition() const    {return _child->GetCurrentSeekPosition();}
   virtual ssize_t GetStreamLength() const           {return _child->GetStreamLength();}

   virtual const IPAddressAndPort & GetSourceOfLastReadPacket() const      {return _child->GetSourceOfLastReadPacket();}
   virtual result_t SetPacketSendDestination(const IPAddressAndPort & iap) {return _child->SetPacketSendDestination(iap);}

private:
   IDataIO * _child;
};

, , IDataIO - , UDPSocketDataIO Seek(), GetCurrentSeekPosition() GetStreamLength(), FileDataIO GetSourceOfLastReadPacket() SetPacketSendDestination(). , , , .

, IDataIO , :

// The bare-minimum interface for any object that we can
// read bytes from, or write bytes to (e.g. TCP or RS232)
class IDataIO
{
public:
   virtual ssize_t Read(void * buffer, size_t size) = 0;
   virtual ssize_t Write(const void * buffer, size_t size) = 0;
};

// A slightly extended interface for objects (e.g. files
// or memory-buffers) that also allows us to seek to a
// specified offset within the data-stream.
class ISeekableDataIO : public IDataIO
{
public:
   virtual result_t Seek(ssize_t offset, int whence) = 0;
   virtual ssize_t GetCurrentSeekPosition() const = 0;
   virtual ssize_t GetStreamLength() const = 0;
};

// A slightly extended interface for packet-oriented
// objects (e.g. UDP sockets)
class IPacketDataIO : public IDataIO
{
public:
   virtual const IPAddressAndPort & GetSourceOfLastReadPacket() const = 0;
   virtual result_t SetPacketSendDestination(const IPAddressAndPort & iap) = 0;
};

.... UDPSocketDataIO - IPacketDataIO FileDataIO ISeekableDataIO, TCPSocketDataIO - IDataIO, . , - , , no-op/stub , , .

, , , - XorDataIO ? , XorDataIO, a XorSeekableDataIO a XorPacketDataIO, , - / , , , .

- / , ?

+4
1

, / , , :

1) " " :

class ISeekableDataIO : public virtual IDataIO {...}
class IPacketDataIO   : public virtual IDataIO {...}

2) DecoratorDataIO, , , , IDataIO:

class DecoratorDataIO : public IPacketDataIO, public ISeekableDataIO
{
public:
   DecoratorDataIO(const IDataIO * childIO)
      : _childIO(childIO)
      , _seekableChildIO(dynamic_cast<ISeekableDataIO *>(childIO))
      , _packetChildIO(dynamic_cast<IPacketDataIO *>(childIO))
   {
      // empty
   }

   virtual ~DecoratorDataIO() {delete _childIO;}

   // IDataIO interface implementation
   virtual ssize_t Read(void * buffer, size_t size) {return _childIO() ? _childIO()->Read(buffer, size) : -1;}
   virtual ssize_t Write(const void * buffer, size_t size) {return _childIO() ? _childIO()->Write(buffer, size) : -1;}

   // ISeekableDataIO interface implementation
   virtual result_t Seek(ssize_t offset, int whence) {return _seekableChildIO ? _seekableChildIO->Seek(offset, whence) : B_ERROR;}
   virtual ssize_t GetCurrentSeekPosition() const {return _seekableChildIO ? _seekableChildIO->GetCurrentSeekPosition() : -1;}
   virtual ssize_t GetStreamLength() const {return _seekableChildIO ? _seekableChildIO->GetStreamLength() : -1;}

   // IPacketDataIO interface implementation
   virtual const IPAddressAndPort & GetSourceOfLastReadPacket() const {return _packetChildIO ? _packetChildIO->GetSourceOfLastReadPacket() : GetDefaultObjectForType<IPAddressAndPort>();}
   virtual const IPAddressAndPort & GetPacketSendDestination() const  {return _packetChildIO ? _packetChildIO->GetPacketSendDestination()  : GetDefaultObjectForType<IPAddressAndPort>();}

private:
   IDataIO * _childIO;
   ISeekableDataIO * _seekableChildIO;
   IPacketDataIO   * _packetChildIO;
};

3) DecoratorDataIO , ( ):

class XorDataIO : public DecoratorDataIO
{  
public:
   XorDataIO(IDataIO * child) : DecoratorDataIO(child) {/* empty */}

   virtual ssize_t Read(void * buffer, size_t size)
   {  
      ssize_t ret = DecoratorDataIO::Read(buffer, size);
      if (ret > 0) XorData(buffer, ret);
      return ret;
   }

   virtual ssize_t Write(const void * buffer, size_t size)
   {  
      XorData(buffer, size);   // const-violation here, but you get the idea
      return DecoratorDataIO::Write(buffer, size);
   }
};

, (.. dynamic_cast < > ), , DecoratorDataIO .

0
source

Source: https://habr.com/ru/post/1679297/


All Articles