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.