Design Patterns
Resource Management
Access Control
Software Architecture
Concurrency Control

Design pattern to limit access to a shared resource

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Design patterns are standard solutions to common problems in software design. One of these recurrent problems is ensuring controlled access to a shared resource in a multi-threaded or distributed environment. A shared resource might be anything from a file, a network connection, to an expensive object in terms of computation or memory. Unrestricted access to such resources can lead to issues like race conditions, deadlocks, and overuse of resources, making efficient and secure access mechanisms crucial.

Singleton Pattern

This pattern ensures that a class has only one instance and provides a global point of access to it. It’s particularly useful when managing access to a resource that is global in scope.

Implementation Strategy:

To implement a Singleton pattern, you make the class constructor private, provide a static method that returns the instance of the class, and ensure that only one instance of the class is created.

java
1public class DatabaseConnector {
2  private static DatabaseConnector instance;
3
4  private DatabaseConnector() {
5    // initialize connection
6  }
7
8  public static synchronized DatabaseConnector getInstance() {
9    if (instance == null) {
10      instance = new DatabaseConnector();
11    }
12    return instance;
13  }
14}

The synchronized keyword ensures thread safety in creating the instance, which is critical in multi-threading environments.

Semaphore Pattern

A semaphore controls access to a common resource by multiple processes in a concurrent system such as a multitasking operating system.

Implementation Strategy:

Semaphores can manage an arbitrary number of resources by using a counter to track the number of resources available. A semaphore with a count of 1 is known as a binary semaphore, which can be used as a mutex or lock.

java
1import java.util.concurrent.Semaphore;
2
3public class PrintQueue {
4  private final Semaphore semaphore;
5
6  public PrintQueue() {
7    semaphore = new Semaphore(1); // Binary semaphore
8  }
9
10  public void printJob(Object document) {
11    try {
12      semaphore.acquire();
13      // Code to perform the printing job
14    } finally {
15      semaphore.release();
16    }
17  }
18}

Proxy Pattern

The Proxy pattern provides a surrogate or placeholder object controlling access to the original object, allowing you to perform something before or after the request gets through to the original object.

Implementation Strategy:

The protective Proxy is useful when you want to control access to a resource based on access rights.

java
1public interface DatabaseAccess {
2  void displayRecords();
3}
4
5public class RealDatabaseAccess implements DatabaseAccess {
6  public void displayRecords() {
7    // Access the database and display records
8  }
9}
10
11public class ProxyDatabaseAccess implements DatabaseAccess {
12  private RealDatabaseAccess realAccess;
13  private boolean hasAccess;
14
15  public ProxyDatabaseAccess(boolean has_access) {
16    this.hasAccess = has_access;
17    realAccess = new RealDatabaseAccess();
18  }
19
20  public void displayRecords() {
21    if (this.hasAccess) {
22      realAccess.displayRecords();
23    } else {
24      System.out.println("Access Denied");
25    }
26  }
27}
Pattern NameUse CaseKey BenefitImplementation Complexity
SingletonEnsures a class only has one instance and provides a global access point to it.Reduces resource usage by limiting instantiation.Easy
SemaphoreManages access to a resource pool for concurrent processes.Controls the number of concurrent accesses to a resource.Moderate
ProxyProvides a placeholder or intermediary layer controlling the access to a resource.Adds a layer of protection and control over the resource access.Moderate

Summary

Selecting the appropriate pattern depends largely on the specific constraints and requirements of the software being developed. While the Singleton pattern is simpler and suited for global resource instances, Semaphore and Proxy patterns offer more fine-grained control over the access and management of resources, making them suitable for more complex scenarios involving concurrency and protection requirements. To implement these patterns effectively, it is crucial to understand their mechanics deeply and recognize the scenarios that best fit their use. This understanding ensures that resources are utilized efficiently and safely in software applications.


Course illustration
Course illustration

All Rights Reserved.