Private Class Data design pattern | Structural Design Pattern

Private Class Data design pattern

The Private Class Data design pattern, also known as the Immutable Pattern, is a structural pattern that involves restricting access to the data members of a class and ensuring that the class's state cannot be modified after its creation. This pattern promotes immutability by making the class's data private and providing read-only access to clients.


Key Components:


1. Private Data Class: Encapsulates the data members of the main class and ensures that they are private, not directly accessible from outside the class.


2. Main Class: Contains methods and behaviors but does not expose the internal state directly. It uses the private data class to manage and store its data.

When to use the Private Class Data (Immutable) pattern:


1. Data Immutability Needed: Use when you want to ensure that the data members of a class cannot be modified after the object is created. This helps in creating immutable instances.


2. Encapsulation and Information Hiding: Use when you want to encapsulate the internal state of a class and provide controlled access to it, hiding implementation details from clients.


Why to use the Private Class Data pattern:


1. Thread Safety: Immutable objects are inherently thread-safe since their state cannot be changed after creation. This can simplify concurrent programming.


2. Predictable Behavior: Immutability leads to more predictable behavior, making it easier to reason about the state of objects at any point in time.


3. Functional Programming: The pattern aligns well with functional programming principles, where immutability is often emphasized.


Where to use the Private Class Data pattern:


1. Configuration Objects: When creating configuration objects with fixed properties, ensuring that the configuration remains constant can be achieved through immutability.


2. Value Objects: For representing values that should not change once they are set, such as coordinates, dates, or identifiers.


3. Security: In situations where it is crucial to maintain the integrity of an object's state, such as in cryptographic algorithms or security-related components.


4. Concurrency: In multi-threaded environments, immutable objects can simplify concurrent programming by eliminating the need for locks or synchronization.


Remember, while immutability has its advantages, it might not be suitable for every scenario, especially when frequent state changes are required. Consider the specific requirements of your application and the characteristics of the problem you're solving.


Example in C#:


// Step 1: Private Data Class

public class PrivateData

{

    private int value1;

    private string value2;


    public PrivateData(int value1, string value2)

    {

        this.value1 = value1;

        this.value2 = value2;

    }


    public int GetValue1()

    {

        return value1;

    }


    public string GetValue2()

    {

        return value2;

    }

}


// Step 2: Main Class using Private Data

public class MainClass

{

    private readonly PrivateData privateData;


    public MainClass(int value1, string value2)

    {

        this.privateData = new PrivateData(value1, value2);

    }


    public void DisplayValues()

    {

        Console.WriteLine($"Value 1: {privateData.GetValue1()}, Value 2: {privateData.GetValue2()}");

    }

}


// Client Code

class Program

{

    static void Main()

    {

        // Create MainClass with initial values

        MainClass mainObject = new MainClass(42, "Hello");


        // Display values (read-only)

        mainObject.DisplayValues();

    }

}



In this example, `PrivateData` is the private data class containing the internal state of the `MainClass`. `MainClass` uses an instance of `PrivateData` to manage its data. The internal state is encapsulated, and clients can only access the data through read-only methods, promoting immutability and encapsulation.

Real-world example in C# where the Private Class Data (Immutable) pattern might be applied. We'll use a `Person` class to represent an individual with immutable attributes:


using System;


// Step 1: Private Data Class

public class PersonData

{

    private readonly string firstName;

    private readonly string lastName;

    private readonly DateTime dateOfBirth;


    public PersonData(string firstName, string lastName, DateTime dateOfBirth)

    {

        this.firstName = firstName;

        this.lastName = lastName;

        this.dateOfBirth = dateOfBirth;

    }


    public string FirstName => firstName;

    public string LastName => lastName;

    public DateTime DateOfBirth => dateOfBirth;

}


// Step 2: Main Class using Private Data

public class Person

{

    private readonly PersonData personData;


    public Person(string firstName, string lastName, DateTime dateOfBirth)

    {

        this.personData = new PersonData(firstName, lastName, dateOfBirth);

    }


    public void DisplayInformation()

    {

        Console.WriteLine($"Name: {personData.FirstName} {personData.LastName}, Date of Birth: {personData.DateOfBirth.ToShortDateString()}");

    }

}


// Client Code

class Program

{

    static void Main()

    {

        // Create an immutable Person object

        Person person = new Person("John", "Doe", new DateTime(1990, 5, 15));


        // Display person information

        person.DisplayInformation();

    }

}



In this example, `PersonData` is the private data class representing the immutable attributes of a person. The `Person` class uses an instance of `PersonData` to manage the person's data. The `PersonData` properties are read-only, providing a way to access the data without the ability to modify it.


This pattern ensures that once a `Person` object is created, its attributes (first name, last name, and date of birth) cannot be changed, promoting immutability and encapsulation.



Comments