kdocs
GitHub
SC - Software Architecture
SC - Software Architecture
  • About
    • Architectural Requirements (RAs)
    • Architectural Perspectives
  • Software Design
    • Microservices
      • Patterns
    • Monolithic
    • C4 Model
  • Software Architectures
    • Clean Architecture
    • DDD (Domain Driven Design)
      • Strategic Modeling
      • Tactical Modeling
    • Event Driven Architecture
      • CAP Theorem
    • Hexagonal Architecture (Ports and Adapters)
  • Design Patterns
    • Behavioral
    • Creational
    • Data Access
    • Structural
  • Practices
    • Clean Code
    • SOLID
  • Others
    • CQRS
Powered by GitBook
On this page
  • DAO (Data Access Object)
  • Repository
  • Gateway
  • ORM (Object Relational Mapper)
  • Registry
  • Example (without decorators)
  • Example (with decorators) (in typescript)
  1. Design Patterns

Data Access

DAO (Data Access Object)

Also known as TDG (Table Data Gateway), it is a Table oriented pattern. (Oriented to Database a table)

This pattern is intended to interact with your Database tables and return table records.

Following this pattern at risk, DAO methods should not JOIN too many tables.

Too many JOINs allows you to create too many table combinations, thus losing the expected data returned.

Ex.: What do you espect of an Employee DAO? You expect returned data to be of Employees, not Employees and Branches data, or Employees and Roles data.

Repository

Mediates the Domain Layer and the Data Layer (Persistense).

It purpose is to persist Domain Objects and return either Aggregates or Domain Objects.

Persisting Domain Objects means you cannot persist invalid data, because the domain object checks its validity.

And you cannot bring invalid data from the Database either.

They don't return database rows directly, it has layers that parses returned data. (Like a presenter)

Gateway

A way to obtain data from a external system.

ORM (Object Relational Mapper)

  • The ORM responsibility is to MAP the database to the domain.

  • In ORM, the model class mirrors the database table.

    • Usually only primitive types, since they come from the database.

Registry

A well known object (known by all), useful for locating other objects/services.

You can use a Registry to inject dependencies.

Why use this:

  • In Typescript you can inject dependencies by passing the dependent classes as parameters to constructors, but this increases coupling, since any changes at the constructor parameters will break code everywhere you instanciate this Class.

  • Also, using a Registry will significantly reduce the amount of classes passed to constructors.

  • And it will centralize all dependencies in a single Registry class. (Could be a downside)

Registry Pattern is very important for Dependency Injection.

Serves basically as a Dependency pool.

Implementing using Singleton

Registry.ts
export default class Registry {
    private dependencies: {[name: string]: any} = {};
    private static instance: Registry;
    
    private constructor() {}
    
    provide(name: string, dependency: any) {
        this.dependencies[name] = dependency;
    }
    
    inject(name: string) {
        return this.dependencies[name];
    }
    
    static getInstance() {
        if (!Registry.instance) Registry.instance = new Registry();
        return Registry.instance;
    }
}

Use it anywhere on the code to, provide (create) and inject (get) other class instances (dependencies).

Example (without decorators)

This

main.ts
const userDAO = new UserDAO();
new Signup(userDAO);
Signup.ts
class Signup {
    constructor (private readonly userDAO: UserDAO) {}
    
    execute(value: string) {
        this.userDAO.getUserByID(value);
    }
}

Will be substituted by

In the main.ts we instanciate and provide to the Registry all the classes we want.

main.ts
// This will automatically create Registry instance, and set the userDAO instance
Registry.getInstance().provide('userDAO', new UserDAO());

At the Signup.ts for example we will grab the UserDAO instance created in the main.ts. And as you can see, no classes had to be passed to the constructor as parameter.

Signup.ts
class Signup {
    userDAO?: UserDAO;

    constructor () {
        this.userDAO = Registry.getInstance().inject('userDAO');
    }
    
    execute(value: string) {
        this.userDAO?.getUserByID(value);
    }
}

Example (with decorators) (in typescript)

The same example above, will be substituted by:

Registry.ts
export default class Registry {
    // The same as above
}

// decorator for Registry
export function inject(name: string) {
    return function(target: any, propertyKey: string) {
        target[propertyKey] = new Proxy({}, {
            get(target: any, propertyKey: string) {
                const dependency = Registry.getInstance().inject(name);
                return dependency[propertyKey];
            }
        });
    }
}
main.ts
// This will automatically create Registry instance, and set the userDAO instance
Registry.getInstance().provide('userDAO', new UserDAO());
Signup.ts
import { inject, Registry } from 'Regestry';

class Signup {
    @inject('userDao')
    userDAO?: UserDAO;
    
    execute(value: string) {
        this.userDAO?.getUserByID(value);
    }
}

PreviousCreationalNextStructural

Last updated 4 months ago

To work with decorators, we need also to lazy load Signup calls to getUserByID with the .

Proxy