The concept of Facade is there to hide abstractions from core classes. In glim, facades can be used to hold single instances of objects that can be used everywhere during the runtime.

Consider an example of a class namely "Database". A Database class example would be the following;

# database.py
class Database:

  	def __init__(self, config):
      	self.config = config
        self.connection = None
  
  	def connect(self):
				# perform database connection using config
        self.connection = connect_to_db()
    
    def query(sql):
      	# perform database query execution using the db connection
        return self.connection.execute_sql(sql)

This example is a primitive db connection library, so it won't reflect the real world. It is just given to teach the concept of Facades. In this example, you can instantiate an object of Database by the following;

# some_script.py
from database import Database

config = {
		'host': 'localhost',
    'port': 3306,
  	'user': 'root',
  	'password': 'pwd'
}

db = Database(config)
db.connect()

sql = "SELECT 1 FROM test.hello"

print(db.query(sql))

It might be noticed that a database instance could be used when the web server starts and used everywhere in model or service layer. Facades can provide this type of abstraction. So, let's make a Database Facade;

from database import Database
from glim.core import Facade

class DB(Facade):
  	accessor = Database

A typical Facade has two functions namely register and boot. The register function can inject a configuration dict to the accessor object, in this example, namely Database class. The boot function can inject (*args, **kwargs) which can be anything. Therefore, glim can't understand how to boot an object. However, it can automatically use register function with config passed. Glim can boot these objects by the following;

# create the database instance, holds it statically
DB.register(config)

# create the database instance with multiple arguments
DB.boot(*args, **kwargs)

By default, glim has a number of facades. These facades are the following;

Facade nameThe mapped accessor
glim.facades.Configglim.core.Config
glim.facades.Viewglim.component.View
glim.facades.Logglim.log.Log
glim.facades.Databaseglim.db.Database
glim.facades.Ormglim.db.Orm

These mappings provide the mapped accessors to be instantiated in the runtime first and use them everywhere.

🚧

No singletons

Again, this pattern is not a singleton pattern. There exists singleton manner but the implementation is completely different. Singletons mostly use private constructors which is a bad practice.