dimanche 7 mars 2021

How to implement the Builder Design Pattern in the right way?

I have found different implementations of the Builder pattern when learning about design patterns. Some implementations use an interface/abstract-class to represent the builder, others use just an static class. Which one is the right way to implement the Builder Design Pattern?

Below, an implementation using an abstract class(ComputerBuilder)

 public class LaptopBuilder : ComputerBuilder
    {

        Computer computer;

         public LaptopBuilder()

        {

            computer = new Computer("Laptop");

        }

        public override void BuildOS()

        {

            //TODO

        }

        public override void BuildDevice()

        {

            //TODO

        }

        public Computer ComputerType

        {

            get { return computer; }

        }

    }

    public class DesktopBuilder : ComputerBuilder

    {

        Computer computer;

        public DesktopBuilder()

        {

            computer = new Computer("Desktop");

        }

        public override void BuildOS()

        {

            //TODO

        }

         public override void BuildDevice()

        {

            //TODO

        }

         public Computer ComputerType

        {

            get { return computer; }

        }

    }

Below, another implementation, Neither using abstract class nor interface, but an static class instead.

public class User 
{
    //All final attributes
    private final String firstName; // required
    private final String lastName; // required
    private final int age; // optional
    private final String phone; // optional
    private final String address; // optional
 
    private User(UserBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.phone = builder.phone;
        this.address = builder.address;
    }
 
    //All getter, and NO setter to provde immutability
    public String getFirstName() {
        return firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public int getAge() {
        return age;
    }
    public String getPhone() {
        return phone;
    }
    public String getAddress() {
        return address;
    }
 
    @Override
    public String toString() {
        return "User: "+this.firstName+", "+this.lastName+", "+this.age+", "+this.phone+", "+this.address;
    }
 
    public static class UserBuilder 
    {
        private final String firstName;
        private final String lastName;
        private int age;
        private String phone;
        private String address;
 
        public UserBuilder(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }
        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }
        public UserBuilder address(String address) {
            this.address = address;
            return this;
        }
        //Return the finally consrcuted User object
        public User build() {
            User user =  new User(this);
            validateUserObject(user);
            return user;
        }
        private void validateUserObject(User user) {
            //Do some basic validations to check 
            //if user object does not break any assumption of system
        }
    }
}

For more details, check out the full two implementations below: First Implementation Second Implementation

Aucun commentaire:

Enregistrer un commentaire