While working on my demo database manager app, I have coded a previously presented Storage Library. The structure of the library's code and employed design patterns partially follow that of the Secure ADODB project, which was a great help. For instance, I liked its approach to parametrized class instantiation involving the factory design pattern and predeclared classes, but I used a slightly modified approach.
The relevant part of the DataTableADODB class is:
'@PredeclaredId
Implements IDataTableStorage
Private Type TDataTableADODB
Model As DataTableModel
SQL As SQLlib
ADO As ADOlib
AdoCommand As ADODB.Command
AdoRst As ADODB.Recordset
ConnectionString As String
TableName As String
FieldNames() As String
FieldTypes() As ADODB.DataTypeEnum
FieldMap As Scripting.Dictionary
IDs As Variant
TypeCast As FieldFormat
End Type
Private this As TDataTableADODB
Public Function Create(ByVal Model As DataTableModel, _
ByVal ConnectionString As String, _
ByVal TableName As String) As DataTableADODB
Dim Instance As DataTableADODB
Set Instance = New DataTableADODB
Instance.Init Model, ConnectionString, TableName
Set Create = Instance
End Function
Friend Sub Init(ByVal Model As DataTableModel, _
ByVal ConnectionString As String, _
ByVal TableName As String)
Guard.NullReference Model
Guard.EmptyString ConnectionString
Set this.Model = Model
Set this.SQL = SQLlib.Create(TableName)
Set this.ADO = ADOlib.Create
If LCase$(Left$(ConnectionString, 7)) = SQLITE_CONNSTR_PREFIX Then
this.ConnectionString = this.ADO.GetSQLiteConnectionString(ConnectionString)("ADO")
Else
this.ConnectionString = ConnectionString
End If
this.ADO.SetConnectionString this.ConnectionString
this.TableName = TableName
this.ADO.GetTableMeta this.TableName, this.FieldNames, this.FieldTypes, this.FieldMap
End Sub
The class implements the IDataTableStorage interface and encapsulates a set of private attributes. It defines a conventionally named factory method Create used for parameterized object instantiation. Here, Create is defined as a Public Function (it should return the new instance), which only news the class (creates an uninitialized instance) and calls the constructor Init on the new instance. Init, having the same parameter signature as Create, is a Sub responsible for initialization and input validation. Init is only called once (from Create), but it needs to be at least Friend to be accessible from the factory.
Another interesting matter is whether the factory should return the default interface (DataTableADODB) or the implemented interface (IDataTableStorage). My understanding is that, in general, there is only a subtle difference. One particular example is when, after creation, a method is called on the implemented interface of the new object, and then it is discarded. If the factory returns the implemented interface, then the calls can be chained. Otherwise, the calling code is responsible for switching the interface and must assign the new object reference to a local variable before such a call.