I've reproduced the example of thisvideo where dependency inversion principle is explained by Tim Corey based on C#
I had some trouble understanding the scope of theLogger andMessageSender properties and how to set them with theCreate function inside theChore class
Also:
With Rubberduck inspections I receive Property *** has no getter
I would appreciate your feedback over the implementation
Link to thefinished file (Dependency inversion principle applied)
Link to theinitial file (Before DIP applied)
Note: UsedRubberduck VBA to set the attributes
To reproduce just run the TestProgram sub in the Macros module
Module:Macros
'@Folder("Program")Option ExplicitPublic Sub TestProgram() Dim programtest As New Program programtest.MainEnd SubClass:Chore
'@Folder("Chores")'@PredeclaredIDOption ExplicitPrivate Type TChore ChoreName As String Owner As person HoursWorked As Double IsComplete As Boolean Logger As ILogger MessageSender As IMessageSenderEnd TypePrivate this As TChoreImplements IChorePublic Sub PerformedWork(ByVal hours As Double) this.HoursWorked = this.HoursWorked + hours this.Logger.Log "Performes work on " & this.ChoreNameEnd SubPublic Sub CompleteChore() IsComplete = True this.Logger.Log "Completed " & this.ChoreName this.MessageSender.SendMessage this.Owner, "The chore " & this.ChoreName & " is complete"End SubPublic Property Set Logger(ByVal Logger As ILogger) Set this.Logger = LoggerEnd PropertyPublic Property Set MessageSender(ByVal MessageSender As IMessageSender) Set this.MessageSender = MessageSenderEnd PropertyPublic Property Get Self() As Chore Set Self = MeEnd PropertyPublic Function Create(ByVal Logger As ILogger, ByVal MessageSender As IMessageSender) As Chore With New Chore Set .Logger = Logger Set .MessageSender = MessageSender Set Create = .Self End WithEnd FunctionPublic Property Get Owner() As IPerson Set Owner = this.OwnerEnd PropertyPublic Property Let Owner(ByVal value As IPerson) Set this.Owner = valueEnd PropertyPublic Property Get ChoreName() As String ChoreName = this.ChoreNameEnd PropertyPublic Property Let ChoreName(ByVal value As String) this.ChoreName = valueEnd PropertyPublic Property Get HoursWorked() As Double HoursWorked = this.HoursWorkedEnd PropertyPublic Property Let HoursWorked(ByVal value As Double) this.HoursWorked = valueEnd PropertyPublic Property Get IsComplete() As Boolean IsComplete = this.IsCompleteEnd PropertyPublic Property Let IsComplete(ByVal value As Boolean) this.IsComplete = valueEnd PropertyPrivate Property Set IChore_Owner(ByVal Owner As IPerson) Set this.Owner = OwnerEnd PropertyPrivate Property Get IChore_Owner() As IPerson Set IChore_Owner = this.OwnerEnd PropertyPrivate Sub IChore_PerformedWork(ByVal hours As Double) PerformedWork hoursEnd SubPrivate Sub IChore_CompleteChore() CompleteChoreEnd SubPrivate Property Get IChore_ChoreName() As String IChore_ChoreName = this.ChoreNameEnd PropertyPrivate Property Let IChore_ChoreName(ByVal value As String) this.ChoreName = valueEnd PropertyPrivate Property Get IChore_HoursWorked() As Double IChore_HoursWorked = this.HoursWorkedEnd PropertyPrivate Property Let IChore_HoursWorked(ByVal value As Double) this.HoursWorked = valueEnd PropertyPrivate Property Get IChore_IsComplete() As Boolean IChore_IsComplete = this.IsCompleteEnd PropertyPrivate Property Let IChore_IsComplete(ByVal value As Boolean) this.IsComplete = valueEnd PropertyClass:Emailer
'@Folder("MessageSenders")'@PredeclaredIDOption ExplicitImplements IMessageSenderPublic Sub SendMessage(ByVal person As IPerson, ByVal message As String) Debug.Print "Simulating sending an email to " & person.EmailAddress & " saying " & messageEnd SubPrivate Sub IMessageSender_SendMessage(ByVal person As IPerson, ByVal message As String) SendMessage person, messageEnd SubClass:Factory
'@Folder("Program")'@PredeclaredIDOption ExplicitPublic Function CreatePerson() As IPerson Set CreatePerson = New personEnd FunctionPublic Function CreateChore() As IChore Set CreateChore = Chore.Create(CreateLogger, CreateMessageSender)End FunctionPublic Function CreateLogger() As ILogger Set CreateLogger = New LoggerEnd FunctionPublic Function CreateMessageSender() As IMessageSender Set CreateMessageSender = New EmailerEnd FunctionClass:IChore
'@Folder("Chores")Option ExplicitPublic Sub PerformedWork(ByVal hours As Double)End SubPublic Sub CompleteChore()End SubPublic Property Get ChoreName() As StringEnd PropertyPublic Property Let ChoreName(ByVal value As String)End PropertyPublic Property Get HoursWorked() As DoubleEnd PropertyPublic Property Let HoursWorked(ByVal value As Double)End PropertyPublic Property Get IsComplete() As BooleanEnd PropertyPublic Property Let IsComplete(ByVal value As Boolean)End PropertyPublic Property Get Owner() As IPersonEnd PropertyPublic Property Set Owner(ByVal value As IPerson)End PropertyClass:ILogger
'@Folder("Loggers")Option ExplicitPublic Sub Log(ByVal message As String)End SubClass:IMessageSender
'@Folder("MessageSenders")Option ExplicitPublic Sub SendMessage(ByVal person As IPerson, ByVal message As String)End SubClass:IPerson
'@Folder("People")Option ExplicitPublic Property Get FirstName() As StringEnd PropertyPublic Property Let FirstName(ByVal value As String)End PropertyPublic Property Get LastName() As StringEnd PropertyPublic Property Let LastName(ByVal value As String)End PropertyPublic Property Get PhoneNumber() As StringEnd PropertyPublic Property Let PhoneNumber(ByVal value As String)End PropertyPublic Property Get EmailAddress() As StringEnd PropertyPublic Property Let EmailAddress(ByVal value As String)End PropertyClass:Logger
'@Folder("Loggers")'@PredeclaredIDOption ExplicitImplements ILoggerPublic Sub Log(ByVal message As String) Debug.Print "Write to console: " & messageEnd SubPrivate Sub ILogger_Log(ByVal message As String) Log messageEnd SubClass:Person
'@Folder("People")Option ExplicitPrivate Type TPerson FirstName As String LastName As String PhoneNumber As String EmailAddress As StringEnd TypePrivate this As TPersonImplements IPersonPublic Property Get FirstName() As String FirstName = this.FirstNameEnd PropertyPublic Property Let FirstName(ByVal value As String) this.FirstName = valueEnd PropertyPublic Property Get LastName() As String LastName = this.LastNameEnd PropertyPublic Property Let LastName(ByVal value As String) this.LastName = valueEnd PropertyPublic Property Get PhoneNumber() As String PhoneNumber = this.PhoneNumberEnd PropertyPublic Property Let PhoneNumber(ByVal value As String) this.PhoneNumber = valueEnd PropertyPublic Property Get EmailAddress() As String EmailAddress = this.EmailAddressEnd PropertyPublic Property Let EmailAddress(ByVal value As String) this.EmailAddress = valueEnd PropertyPrivate Property Get IPerson_FirstName() As String IPerson_FirstName = this.FirstNameEnd PropertyPrivate Property Let IPerson_FirstName(ByVal value As String) FirstName = valueEnd PropertyPrivate Property Get IPerson_LastName() As String IPerson_LastName = this.LastNameEnd PropertyPrivate Property Let IPerson_LastName(ByVal value As String) LastName = valueEnd PropertyPrivate Property Get IPerson_PhoneNumber() As String IPerson_PhoneNumber = this.PhoneNumberEnd PropertyPrivate Property Let IPerson_PhoneNumber(ByVal value As String) PhoneNumber = valueEnd PropertyPrivate Property Get IPerson_EmailAddress() As String IPerson_EmailAddress = this.EmailAddressEnd PropertyPrivate Property Let IPerson_EmailAddress(ByVal value As String) EmailAddress = valueEnd PropertyClass:Program
'@Folder("Program")Option ExplicitPublic Sub Main() Dim Owner As IPerson Set Owner = Factory.CreatePerson Owner.FirstName = "Tim" Owner.LastName = "Corey" Owner.EmailAddress = "[email protected]" Owner.PhoneNumber = "555-1212" Dim newChore As IChore Set newChore = Factory.CreateChore newChore.ChoreName = "Take out the trash" Set newChore.Owner = Owner newChore.PerformedWork 3 newChore.PerformedWork 1.5 newChore.CompleteChoreEnd SubClass:Texter
'@Folder("MessageSenders")'@PredeclaredIDOption ExplicitImplements IMessageSenderPublic Sub SendMessage(ByVal person As IPerson, ByVal message As String) Debug.Print "I am texting " & person.FirstName & " to say " & messageEnd SubPrivate Sub IMessageSender_SendMessage(ByVal person As IPerson, ByVal message As String) SendMessage person, messageEnd Sub1 Answer1
An observation on your class constructors. At the moment you are using public properties to allow you to set the value of properties of a class after it has been created. You can take this to the next step which allows you to delete the setters for the public class members by passing the create parameters to the Self function.
In this way you can create objects with immutable properties from parameters that are provided at the time of object creation.
Public Function Create(ByVal Logger As ILogger, ByVal MessageSender As IMessageSender) As Chore With New Chore Set Create = .Self(Logger, MessageSender) End WithEnd FunctionPublic Function Self(ByVal Logger As ILogger, ByVal MessageSender As IMessageSender) As Chore' This code runs internal to the newly created instance Set this.Logger = Logger Set this.MessageSender = MessageSender Set Self = Me End Property- 1\$\begingroup\$Except
Selfis a good name for aProperty Getprocedure that returnsMeand does nothing else - I like the idea/approach very much, but it needs a name that better conveys the nature of the side-effects here, likeInitorInitialize, maybe.\$\endgroup\$Mathieu Guindon– Mathieu Guindon2019-11-02 16:28:03 +00:00CommentedNov 2, 2019 at 16:28 - 1\$\begingroup\$I had a think for a name and with the idea of something finished and ready to be presented I came up with Debutante?\$\endgroup\$Freeflow– Freeflow2019-11-02 17:12:23 +00:00CommentedNov 2, 2019 at 17:12
You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.

