Single Access Design Pattern

DTasev
445 views

Open Source Your Knowledge, Become a Contributor

Technology knowledge has to be shared and made accessible for free. Join the movement.

Create Content

Single Access Design Pattern

Table of Contents

  • Table of Contents
  • What is it?
  • When to use it?
  • Class Interface
    • Example usage with tests
    • Coding exercise
    • Final implementation
  • Feedback

What is it?

The Single Access design pattern restricts the access to a resource, allowing only a single retrieval. Consecutive accesses trigger an error, which usually points to a logical error in the code.

The design emerged in a project that uses a shared information object across multiple states. It provides a way to ensure that the shared data is being accessed only once in each state, and being updated at the end. This has helped point out logical errors where the object is being accessed multiple times, or not being set properly, within a state.

The pattern is used in the project like this:

  • When a new state is entered, the necessary shared information is retrieved and stored in instance variables. The instance variables can be changed.
  • Trying to retrieve the information from the shared object a second time triggers an access error.
  • Not setting the shared information at the end of a state triggers an error in the next access.

As this design controls the ownership of an object, it is similar to C++11's std::unique_ptr. It also enforces that when a state reads some of the shared information, it must also write back the updated information.

When to use it?

When you must guarantee that a resource:

  • is only be accessed once by an instance
  • is updated by the instance that accessed it

Class Interface

Interface
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface ISingleAccess<T> {
/** Sets the resource for a single access.
* @param resource The object of the resource.
*/
set(resource: T);
/** Gets the resource.
* Marks it as accessed, and removes any references to the object in this class.
*/
get(): T;
/** Checks if the resource is available.
* @returns true if not accessed and not null, false is accessed or null
*/
available(): boolean;
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

This is what an interface for the single access implementation looks like. The <T> is a generics notation, that allows specifying to TypeScript what the actual object's type is, and also points out that this will work for any object. If you're not familiar with generics, have a look at the TypeScript's Generics documentation.

Example usage with tests

The following file contains some test cases, versus which your implementation will be tested (if you attempt it!). Test cases are a good way of showing off different use cases, while keeping it easy to follow.

Single Access Tests
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import 'mocha';
import { expect } from "chai";
import { SingleAccess } from "./singleAccess";
class MyClass {
n: number;
s: string;
constructor(n, s) {
this.n = n;
this.s = s;
}
}
describe('Single Access Design Pattern', () => {
it('should allow setting a resource', () => {
const singleAccess = new SingleAccess<MyClass>();
const myClass = new MyClass(13, "apples");
singleAccess.set(myClass);
expect(singleAccess.available()).to.be.true;
});
it('should allow getting a resource once', () => {
const singleAccess = new SingleAccess<MyClass>();
const myClass = new MyClass(13, "apples");
singleAccess.set(myClass);
const result = singleAccess.get();
expect(singleAccess.available()).to.be.false;
expect(result === myClass).to.be.true;
});
it('should NOT allow getting a resource more than once', () => {
const singleAccess = new SingleAccess<MyClass>();
const myClass = new MyClass(13, "apples");
singleAccess.set(myClass);
const result = singleAccess.get();
expect(singleAccess.available()).to.be.false;
expect(result === myClass).to.be.true;
try {
const fail = singleAccess.get();
// this should throw an error, if it doesn't then the test must fail, as a second access was allowed
expect(false).to.be.true;
} catch (error) {
expect(error != null);
expect(singleAccess.available()).to.be.false;
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Coding exercise

Implementation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
export class SingleAccess<T> implements ISingleAccess<T> {
// you can add variables too
//
set(resource: T) {
throw new Error("Method not implemented.");
}
get(): T {
throw new Error("Method not implemented.");
}
available(): boolean {
throw new Error("Method not implemented.");
}
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

This is an opportunity to have a go at implementing the design pattern. This will help you understand it better, so I definitely recommend giving it a go.

If you want some guidance for where to start, scroll further down.

If you want the final code, go to the end of the page.























Hints:
  • The resource needs to be stored
  • The access to the resource needs to be tracked
























Final implementation

Implementation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
export class SingleAccess<T> implements ISingleAccess<T> {
private resource: T = null;
private accessed: boolean = false;
set(resource: T) {
this.resource = resource;
this.accessed = false;
}
available(): boolean {
return !this.accessed && this.resource !== null;
}
get(): T {
if (this.available()) {
const x = this.resource;
this.resource = null;
return x;
} else if (this.accessed) {
throw new Error("This object has already been accessed.");
} else if (this.resource === null) {
throw new Error("The resource object has not been set.");
} else {
throw new Error("Unknown error with single access object");
}
}
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Feedback

For feedback or comments, please create an issue or drop me an email dimtasev@gmail.com

Open Source Your Knowledge: become a Contributor and help others learn. Create New Content