Abstracting away a third party components interface.

Posts   
 
    
MarcoP avatar
MarcoP
User
Posts: 270
Joined: 29-Sep-2004
# Posted on: 24-Jan-2005 19:25:01   

We are using a third party fax utility and I am having difficulty abstracting away the faxing interface. I started out with the following interface definitions:

IFax IFaxAttachment IFaxServer

Now, I implemented the following concrete classes that implement the above interfaces.

RightFax RightFaxAttachment RightFaxServer

I think my biggest problem is that the right fax object has a few properties that are specific to the rightfax fax object. So, I was hoping the client could do the following:

IFax MyFax = new RightFax()
IFaxServer MyServer = new RightFaxServer()

// set a few properties on the fax object..

MyServer.Fax(MyFax)

The problem is setting the right fax specific properties. I'm not sure if I am explaining my problem good enough, but I hope you see where I am getting at.

Any suggestions or thoughts?

Thanks!

Posts: 497
Joined: 08-Apr-2004
# Posted on: 24-Jan-2005 21:41:24   

Erm, not too sure what you mean (maybe its me!)..

MarcoP avatar
MarcoP
User
Posts: 270
Joined: 29-Sep-2004
# Posted on: 24-Jan-2005 22:23:11   

MattWoberts wrote:

Erm, not too sure what you mean (maybe its me!)..

Well basically I am trying to avoid programming to implementations, rather interfaces. This way, if we decide to use another 3rd party component or implement the interfaces in another way, the client-side code is guarded against change.

jtgooding
User
Posts: 126
Joined: 26-Apr-2004
# Posted on: 24-Jan-2005 22:42:12   

This is a good way of doing it, the main issue is 'hiding' specific 3rd party implementations.

Analyze what your application needs, not what the 3rd party control requires to function.

If all you need is

Fax.Send(string address)

then hide all the 3rd party stuff, in their, if you need more complex stuff like creating an abstract for an address list (broadcast messages etc) then wrapper that and then implement that.

As I said the key is creating your interfaces to what your application needs not modeling it after 3rd party components. I've done exactly what you are doing with Fax software before, mine looked similar to yours in.

IFaxServer (Init/Config/Send/Receive code) IFaxDocument (Document wrapper) IFaxRecipient (A single fax recipient) IFaxRecipientList (A typed collection of IFaxRecpients)

I believe that was all of my interfaces I used its been a bit over a year since I did it though =)

John

MarcoP avatar
MarcoP
User
Posts: 270
Joined: 29-Sep-2004
# Posted on: 24-Jan-2005 23:33:20   

jtgooding wrote:

This is a good way of doing it, the main issue is 'hiding' specific 3rd party implementations.

Analyze what your application needs, not what the 3rd party control requires to function.

If all you need is

Fax.Send(string address)

then hide all the 3rd party stuff, in their, if you need more complex stuff like creating an abstract for an address list (broadcast messages etc) then wrapper that and then implement that.

As I said the key is creating your interfaces to what your application needs not modeling it after 3rd party components. I've done exactly what you are doing with Fax software before, mine looked similar to yours in.

IFaxServer (Init/Config/Send/Receive code) IFaxDocument (Document wrapper) IFaxRecipient (A single fax recipient) IFaxRecipientList (A typed collection of IFaxRecpients)

I believe that was all of my interfaces I used its been a bit over a year since I did it though =)

John

Great, thx for the info! You dont happen to have a bit of you code left over do you? I would just like to look at it and compare. here is what I have:

 Imports System.Collections.Specialized
Imports Sheakley.Communication.Interfaces

Namespace Sheakley.Communication
    ''' -----------------------------------------------------------------------------
    ''' Project  : Sheakley.Communication
    ''' Struct   : Sheakley.Communication.RightFax
    ''' 
    ''' Copyright (C) 2004, All Rights Reserved
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Concrete RightFax class implementing the IFax interface.
    ''' </summary>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    '''     mpaul   1/24/2005   Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public Class RightFax
        Implements IFax

        ' Private attributes.
        Private _to As String
        Private _from As String
        Private _faxNumber As String
        Private _coversheetFileName As String
        Private _coversheetNotes As StringCollection
        Private _attachments As FaxAttachmentCollection

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Ctor.
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public Sub New()
            _coversheetNotes = New StringCollection
            _attachments = New FaxAttachmentCollection
        End Sub

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Ctor.
        ''' </summary>
        ''' <param name="To"></param>
        ''' <param name="From"></param>
        ''' <param name="FaxNumber"></param>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public Sub New(ByVal [To] As String, ByVal From As String, ByVal FaxNumber As String)
            ' call the default constructor.
            Me.New()

            ' set our private fields.
            _to = [To]
            _from = From
            _faxNumber = FaxNumber
        End Sub

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Gets the attachments collection.
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public ReadOnly Property Attachments() As FaxAttachmentCollection Implements Interfaces.IFax.Attachments
            Get
                Return _attachments
            End Get
        End Property

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Gets and sets the coversheet notes.
        ''' </summary>
        ''' <remarks>
        ''' </remarks> 
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public Property CoversheetNotes(ByVal Index As Integer) As String Implements Interfaces.IFax.CoversheetNotes
            Get
                Return _coversheetNotes.Item(Index)
            End Get
            Set(ByVal Value As String)
                _coversheetNotes.Insert(Index, Value)
            End Set
        End Property

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Gets the total number of coversheet notes.
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public ReadOnly Property TotalCoversheetNotes() As Integer Implements Interfaces.IFax.TotalCoversheetNotes
            Get
                Return _coversheetNotes.Count
            End Get
        End Property

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Gets and sets the coversheet field.
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public Property CoversheetFileName() As String Implements Interfaces.IFax.CoversheetFileName
            Get
                Return _coversheetFileName
            End Get
            Set(ByVal Value As String)
                _coversheetFileName = Value
            End Set
        End Property

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Gets and sets the fax number field.
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public Property FaxNumber() As String Implements Interfaces.IFax.FaxNumber
            Get
                Return _faxNumber
            End Get
            Set(ByVal Value As String)
                _faxNumber = Value
            End Set
        End Property

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Gets and sets the from field.
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public Property From() As String Implements Interfaces.IFax.From
            Get
                Return _from
            End Get
            Set(ByVal Value As String)
                _from = Value
            End Set
        End Property

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Gets and sets the to field.
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public Property [To]() As String Implements Interfaces.IFax.To
            Get
                Return _to
            End Get
            Set(ByVal Value As String)
                _to = Value
            End Set
        End Property
    End Class
End Namespace

 Imports System.IO
Imports Sheakley.Communication.Interfaces

Namespace Sheakley.Communication
    ''' -----------------------------------------------------------------------------
    ''' Project  : Sheakley.Communication
    ''' Struct   : Sheakley.Communication.RightFaxAttachment
    ''' 
    ''' Copyright (C) 2004, All Rights Reserved
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Concrete RightFaxAttachment class implementing the IFaxAttachment interface.
    ''' </summary>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    '''     mpaul   1/24/2005   Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public Class RightFaxAttachment
        Implements IFaxAttachment

        ' Private attributes.
        Private _filename As String

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Ctor.
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public Sub New()
            ' default constructor.
        End Sub

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Ctor.
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public Sub New(ByVal Filename As String)
            _filename = Filename
        End Sub

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Gets and sets the filename value.
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public Property Filename() As String Implements Interfaces.IFaxAttachment.Filename
            Get
                Return _filename
            End Get
            Set(ByVal Value As String)
                ' ensure the file exists on disk.
                If Not File.Exists(Value) Then Throw New FileNotFoundException("File does not exist.")
                _filename = Value
            End Set
        End Property
    End Class
End Namespace


 Imports System.IO
Imports Sheakley.Communication.Interfaces

Namespace Sheakley.Communication
    ''' -----------------------------------------------------------------------------
    ''' Project  : Sheakley.Communication
    ''' Struct   : Sheakley.Communication.RightFaxAttachment
    ''' 
    ''' Copyright (C) 2004, All Rights Reserved
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' Concrete RightFaxAttachment class implementing the IFaxAttachment interface.
    ''' </summary>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    '''     mpaul   1/24/2005   Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public Class RightFaxAttachment
        Implements IFaxAttachment

        ' Private attributes.
        Private _filename As String

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Ctor.
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public Sub New()
            ' default constructor.
        End Sub

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Ctor.
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public Sub New(ByVal Filename As String)
            _filename = Filename
        End Sub

        ''' -----------------------------------------------------------------------------
        ''' <summary>
        ''' Gets and sets the filename value.
        ''' </summary>
        ''' <remarks>
        ''' </remarks>
        ''' <history>
        '''     mpaul   1/25/2005   Created
        ''' </history>
        ''' -----------------------------------------------------------------------------
        Public Property Filename() As String Implements Interfaces.IFaxAttachment.Filename
            Get
                Return _filename
            End Get
            Set(ByVal Value As String)
                ' ensure the file exists on disk.
                If Not File.Exists(Value) Then Throw New FileNotFoundException("File does not exist.")
                _filename = Value
            End Set
        End Property
    End Class
End Namespace

Devildog74
User
Posts: 719
Joined: 04-Feb-2004
# Posted on: 25-Jan-2005 06:48:19   

jtgooding wrote:

Analyze what your application needs, not what the 3rd party control requires to function.

As I said the key is creating your interfaces to what your application needs not modeling it after 3rd party components. I've done exactly what you are doing with Fax software before, mine looked similar to yours in.

IFaxServer (Init/Config/Send/Receive code) IFaxDocument (Document wrapper) IFaxRecipient (A single fax recipient) IFaxRecipientList (A typed collection of IFaxRecpients)

John

All very excellent points. However, if sometimes you need to explicitly deal with a 3rd party interface internally, you could create more "generic" parameters to your interface methods, then check the objects passed in to see of they are of type IThirdPartyInterface. For example, if the IFaxDocument and IFaxRecipient methods might need special handling for this 3rd party harware, pass an object into these methods then check the object to see if it is a 3rd party object. If it is, invoke a strategy to run the code for the 3rd party interactions, otherwise, do what you normally would.

jtgooding
User
Posts: 126
Joined: 26-Apr-2004
# Posted on: 25-Jan-2005 15:31:24   

Devildog74 wrote:

All very excellent points. However, if sometimes you need to explicitly deal with a 3rd party interface internally, you could create more "generic" parameters to your interface methods, then check the objects passed in to see of they are of type IThirdPartyInterface. For example, if the IFaxDocument and IFaxRecipient methods might need special handling for this 3rd party harware, pass an object into these methods then check the object to see if it is a 3rd party object. If it is, invoke a strategy to run the code for the 3rd party interactions, otherwise, do what you normally would.

Aye there is several good ways of calling 3rd party specific functionality in an abstract way, I was just trying to provide a way of thinking, if you need a generic abstraction, you should avoid 3rd party specific implementation when ever possible because no matter what you do it will creep into the 'cleint' side code of the interface and will forever have 'if this interface do this' otherwise 'do this; etc. but sometimes you just have to do it /cringe =)

MarcoP wrote:

Great, thx for the info! You dont happen to have a bit of you code left over do you? I would just like to look at it and compare. here is what I have:

Marco, Sorry I no longer work for the company I wrote that for and they would consider it proprietary information since its one of the benefits of their system over their competition rage

As for the code you have it looks like a nice start, if you need to multi-cast (fax broadcast) you will need to make some changes, the biggest pain of what I worked on was document generation, our documents were all generated in real time with client data in them so we had to go through conversion processes to get our custom documents into TIFF/PCX/DCX formats for fax servers.

I used the same process to render our documents to PDF and other formats for emailing through this same process. My interfaces were based on 'document delivery' rather than 'fax', 'email' or 'web' etc. So I abstracted a bit higher than you currently are and used the same document, and delivery engines for various delivery methods.

John