Android Tutorial [B4X] Builder Pattern

Reference: https://en.wikipedia.org/wiki/Builder_pattern
Reference 2: My head, sorry for my english :p
BuilderLabel
BuilderButton
PatternCreator

Builder pattern
Builder pattern is one the most important design pattern in OOP. The main purpose of this pattern is to validate an object before inizializing it, but without checking the object in his class costructor. A builder pattern has also more advantages, that we will see in this tutorial

Inizialize an object

We have different ways to make a new object. Usually we do this:
B4X:
Dim lb As Label
lb.Initialize("")
lb.SetLayout(0,0,1,1)
lb.Gravity = Gravity.CENTER
lb.Typeface = Typeface.DEFAULT
lb.Textsize = 14
lb.Text = "Some text"
'etc etc
but if we want to make more than one label, we have to write many lines of code (or use a loop, of course). Another way is to make a costructor:
B4X:
Public Sub MakeLabel(Event As String, left As Int, top As Int, width As Int, height As Int, mGravity As Int, mTypeface As Typeface, textsize As Int, text As String) As Label
    Dim l As Label
    l.Initialize(Event)
    l.SetLayout(left,top,width,height)
    l.Text = text
    l.TextSize = textsize
    l.Gravity = mGravity
    l.Typeface = mTypeface
    Return l
End Sub
Dim lb As Label = MakeLabel("",0,0,1,1,Gravity.CENTER,Typeface.DEFAULT,14,"Some text")
but at first sight it is difficult to find an error while passing parameters, making the code unreadable.

Make the pattern
To avoid the issues explained previous, we can use a Builder Pattern. Make a new class (I usually call it Builder*, replacing * with our class name).

B4X:
Sub Class_Globals
    Private mSex As Int
    Private mAge As Int
    Private mName As String
 
 
    Public const MALE As Int = 0
    Public const FEMALE As Int = 1
 
    'You can use type or another class
    Type Animal(Name As String, Sex As Int, Age As Int)
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize As BuilderAnimal
    Return Me
End Sub

Public Sub Sex (pSex As Int) As BuilderAnimal
    If pSex < 0 Or pSex > 1 Then
        Log("Sex error, set male as default")
        mSex = MALE
    End If
    mSex = pSex
    Return Me
End Sub

Public Sub Age (pAge As Int) As BuilderAnimal
    If pAge < 0 Then
        Log("Wrong age!")
        mAge = 0
    End If
    mAge = pAge
    Return Me
End Sub

Public Sub Name (pName As String) As BuilderAnimal
    mName = pName
    Return Me
End Sub

Public Sub Build As Animal
    Dim n As Animal
    n.Initialize
    n.name = mName
    n.sex = mSex
    Return n
End Sub

[ADVANTAGES]
Avoid repetition of names

In c# we can instantiate a new object in this way:
B4X:
TextBlock b = new TextBlock()
            {
                Margin = new Thickness(0, 0, 0, 0),
                MaxHeight = 0,
                MaxWidth = 0,
                FontSize = 18,
            };

In B4 we need to do this:
B4X:
Dim dog    As Animal
dog.Initialize
dog.Age = 20
dog.Name = "Rex"
dog.Sex = 0

Using builder pattern we can do in this way:
B4X:
Dim builder As BuilderAnimal
builder.Initialize _
    .Name("Rex") _
    .Sex(builder.FEMALE) _
    .Age(20)
Dim dog As Animal = builder.Build

Clone object
Each of us would like to be able to do something like this:
B4X:
Dim lb as label
lb.initialize("")
'.... ..... .....

dim lb2 as label = lb
lb2.setLayout(0,0,1,1)
but this doesn't make a new copy of the previous label (lb2 is a pointer to previous label, so each change we do in lb2 is done in lb1). Using builder pattern we can do this:
B4X:
Dim builder As BuilderAnimal
builder.Initialize _
    .Name("Rex") _
    .Sex(builder.FEMALE) _
    .Age(20)

Dim dog As Animal = builder.Build
Dim cat As Animal = builder.Build
Dim monkey As Animal = builder.Name("Giaquinto").Build

Log(dog)
Log(cat)
Log(monkey)

'Log
'[Age=0, IsInitialized=true, Name=Rex, Sex=1]
'[Age=0, IsInitialized=true, Name=Rex, Sex=1]
'[Age=0, IsInitialized=true, Name=Giaquinto, Sex=1]




 
Last edited:

Emme Developer

Well-Known Member
Licensed User
Longtime User
BuilderLabel
I attach builder pattern that i use to create label.

B4X:
Sub Activity_Create(FirstTime As Boolean)
    Dim Bl As BuilderLabel
    Bl.Initialize _
        .Text("New label OhYEah") _
        .TextColor(Colors.RGB(Rnd(0,255),Rnd(0,255),Rnd(0,255))) _
        .sTypeface(Typeface.DEFAULT) _
        .TextSize(Rnd(10,20)) _
        
    Dim lb1 As Label = Bl.setLayout(0,0,100dip,100dip).Build
    Dim lb2 As Label = Bl.setLayout(0,120dip,100dip,100dip).Build
    Dim lb3 As Label = Bl.setLayout(0,220dip,100dip,100dip).Build
    
    
    Activity.AddView(lb1,lb1.Left,lb1.Top,lb1.Width,lb1.Height)
    Activity.AddView(lb2,lb2.Left,lb2.Top,lb2.Width,lb2.Height)
    Activity.AddView(lb3,lb3.Left,lb3.Top,lb3.Width,lb3.Height)
End Sub
 

Attachments

  • BuilderLabel.bas
    3.2 KB · Views: 365

Emme Developer

Well-Known Member
Licensed User
Longtime User
BuilderButton
I attach builder pattern that i use to create Button. Some information: Usually BuilderPattern is not used to make view. When a view is initialized in class, it get the activity context of the class, so events are handled in class module. If you want to handle the event in activity in which is inizialized the Builder, you need to call the sub using a callback.

B4X:
Sub Activity_Create(FirstTime As Boolean)
    Dim BB As BuilderButton
    BB.Initialize(Me) _
        .Text("New fantastic Button") _
        .TextColor(Colors.RGB(Rnd(0,255),Rnd(0,255),Rnd(0,255))) _
        .sTypeface(Typeface.DEFAULT) _
        .TextSize(Rnd(10,20)) _
       
    Dim btn1 As Button = BB.EventName("btn1").tag(Rnd(0,500)).Build
    Dim btn2 As Button = BB.EventName("btn2").tag(Rnd(0,500)).Build
    Dim btn3 As Button = BB.EventName("btn3").tag(Rnd(0,500)).Build
   
    Activity.AddView(btn1,0,0,100dip,100dip)
    Activity.AddView(btn2,0,120dip,100dip,100dip)
    Activity.AddView(btn3,0,220dip,100dip,100dip)
   
End Sub

Sub btn1_Click (send As Object)
    Dim sends As View = send
    Log($"btn1 clicked. Tag: ${sends.tag}"$)
End Sub

Sub btn2_Click (send As Object)
    Dim sends As View = send
    Log($"btn2 clicked. Tag: ${sends.tag}"$)
End Sub

Sub btn3_Click (send As Object)
    Dim sends As View = send
    Log($"btn3 clicked. Tag: ${sends.tag}"$)
End Sub
 

Attachments

  • BuilderButton.bas
    3.2 KB · Views: 342
Top