4
\$\begingroup\$

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 Sub

Class: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 Property

Class: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 Sub

Class: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 Function

Class: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 Property

Class:ILogger

'@Folder("Loggers")Option ExplicitPublic Sub Log(ByVal message As String)End Sub

Class:IMessageSender

'@Folder("MessageSenders")Option ExplicitPublic Sub SendMessage(ByVal person As IPerson, ByVal message As String)End Sub

Class: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 Property

Class: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 Sub

Class: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 Property

Class: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 Sub

Class: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 Sub
askedNov 2, 2019 at 13:44
Ricardo Diaz's user avatar
\$\endgroup\$

1 Answer1

5
\$\begingroup\$

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
answeredNov 2, 2019 at 14:18
Freeflow's user avatar
\$\endgroup\$
2
  • 1
    \$\begingroup\$ExceptSelf is a good name for aProperty Get procedure that returnsMe and 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, likeInit orInitialize, maybe.\$\endgroup\$CommentedNov 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\$CommentedNov 2, 2019 at 17:12

You mustlog in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.