# On Premises and Design patterns applied
###### tags: `Design Pattern`
## On premises
### What is on premises?
On-premises refers to IT infrastructure hardware and software applications that are **hosted on-site (就地部屬)**. This contrasts with IT assets that are hosted by a public cloud platform or remote data center. Businesses have more control of on-premises IT assets by maintaining the performance, security and upkeep, as well as the physical location.
### Why is there still demand for on premises?
**Disadvantages of cloud service: Privacy Issues**
The availability of information can be breached when usingcloud computing. Your data can be accessed by unauthorizedentities or even modified.
### The reason of applying design patterns
- Keep single code base for a product for both web app and on premise with the consideration for future update
- Yet, APIs and request header token for the 2 scenario are different for identical purpose. Ex: creating a project through api
- web app: stored in the cloud. Need CRUD
- on premise: creating project stored in local SQLite db. Need CRUD
- Encapsulate the logic (ex: which api to call) in one place, making rest of the code base (ex: where one of the api need to be called) remained unchanged
- ETC (Easy to change)
<br>
## Applied design patterns brief intro
### Strategy design pattern
> Strategy is a behavioral design pattern that lets you define a family of algorithms, put each of them into a separate class, and make their objects interchangeable.
> Enable the exact behavior of a system to be selected at run-time
#### Life analogy
<u>Making hot drink</u>
- Making coffee
- water preparation: Boil water 200ml, lower temperature to 90 degree
- making drink: grind one spoon of coffee beans into power, slowing pour hot water in
- Making black tea
- water preparation: Boil water 500ml
- making drink: put teabag into the bottle, pour the water in, remove teabag after 2 min
:::success
**Why applying this design pattern?**
Both web app and on premise have identical method (ex: CRUD project)
:::
#### Code example
```typescript=
/**
* The Context defines the interface of interest to clients.
*/
class Context {
private strategy: Strategy;
/**
* Usually, the Context accepts a strategy through the constructor, but also
* provides a setter to change it at runtime.
*/
constructor(strategy: Strategy) {
this.strategy = strategy;
}
/**
* Usually, the Context allows replacing a Strategy object at runtime.
*/
public setStrategy(strategy: Strategy) {
this.strategy = strategy;
}
/**
* The Context delegates some work to the Strategy object instead of
* implementing multiple versions of the algorithm on its own.
*/
public doSomeBusinessLogic(): void {
// ...
console.log('Context: Sorting data using the strategy (not sure how it\'ll do it)');
const result = this.strategy.doAlgorithm(['a', 'b', 'c', 'd', 'e']);
console.log(result.join(','));
// ...
}
}
/**
* The Strategy interface declares operations common to all supported versions
* of some algorithm.
*
* The Context uses this interface to call the algorithm defined by Concrete
* Strategies.
*/
interface Strategy {
doAlgorithm(data: string[]): string[];
}
/**
* Concrete Strategies implement the algorithm while following the base Strategy
* interface. The interface makes them interchangeable in the Context.
*/
class ConcreteStrategyA implements Strategy {
public doAlgorithm(data: string[]): string[] {
return data.sort();
}
}
class ConcreteStrategyB implements Strategy {
public doAlgorithm(data: string[]): string[] {
return data.reverse();
}
}
/**
* The client code picks a concrete strategy and passes it to the context. The
* client should be aware of the differences between strategies in order to make
* the right choice.
*/
const context = new Context(new ConcreteStrategyA());
console.log('Client: Strategy is set to normal sorting.');
context.doSomeBusinessLogic();
console.log('');
console.log('Client: Strategy is set to reverse sorting.');
context.setStrategy(new ConcreteStrategyB());
context.doSomeBusinessLogic();
```
log result
```
Client: Strategy is set to normal sorting.
Context: Sorting data using the strategy (not sure how it'll do it)
a,b,c,d,e
Client: Strategy is set to reverse sorting.
Context: Sorting data using the strategy (not sure how it'll do it)
e,d,c,b,a
```
<br>
### Factory design pattern
> Factory method is a creational design pattern which solves the problem of creating product objects without specifying their concrete classes.
> A component responsible solely for the wholesale creation of objects
#### Life analogy
<u>Logistic management</u>
<img src="https://refactoring.guru/images/patterns/content/factory-method/factory-method-en.png?id=cfa26f33dc8473e803fadae0d262100a"/>
:::success
**Why applying this design pattern?**
We want to decide with set of CRUD api to use without passing params everytime
:::
#### Code sample
```typescript
/**
* The Creator class declares the factory method that is supposed to return an
* object of a Product class. The Creator's subclasses usually provide the
* implementation of this method.
*/
abstract class Creator {
/**
* Note that the Creator may also provide some default implementation of the
* factory method.
*/
public abstract factoryMethod(): Product;
/**
* Also note that, despite its name, the Creator's primary responsibility is
* not creating products. Usually, it contains some core business logic that
* relies on Product objects, returned by the factory method. Subclasses can
* indirectly change that business logic by overriding the factory method
* and returning a different type of product from it.
*/
public someOperation(): string {
// Call the factory method to create a Product object.
const product = this.factoryMethod();
// Now, use the product.
return `Creator: The same creator's code has just worked with ${product.operation()}`;
}
}
/**
* Concrete Creators override the factory method in order to change the
* resulting product's type.
*/
class ConcreteCreator1 extends Creator {
/**
* Note that the signature of the method still uses the abstract product
* type, even though the concrete product is actually returned from the
* method. This way the Creator can stay independent of concrete product
* classes.
*/
public factoryMethod(): Product {
return new ConcreteProduct1();
}
}
class ConcreteCreator2 extends Creator {
public factoryMethod(): Product {
return new ConcreteProduct2();
}
}
/**
* The Product interface declares the operations that all concrete products must
* implement.
*/
interface Product {
operation(): string;
}
/**
* Concrete Products provide various implementations of the Product interface.
*/
class ConcreteProduct1 implements Product {
public operation(): string {
return '{Result of the ConcreteProduct1}';
}
}
class ConcreteProduct2 implements Product {
public operation(): string {
return '{Result of the ConcreteProduct2}';
}
}
/**
* The client code works with an instance of a concrete creator, albeit through
* its base interface. As long as the client keeps working with the creator via
* the base interface, you can pass it any creator's subclass.
*/
function clientCode(creator: Creator) {
// ...
console.log('Client: I\'m not aware of the creator\'s class, but it still works.');
console.log(creator.someOperation());
// ...
}
/**
* The Application picks a creator's type depending on the configuration or
* environment.
*/
console.log('App: Launched with the ConcreteCreator1.');
clientCode(new ConcreteCreator1());
console.log('');
console.log('App: Launched with the ConcreteCreator2.');
clientCode(new ConcreteCreator2());
```
log result
```
App: Launched with the ConcreteCreator1.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct1}
App: Launched with the ConcreteCreator2.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct2}
```
<br>
### Singleton design pattern
> Singleton is a creational design pattern that lets you ensure that a class **has only one instance**, while providing a global access point to this instance.
<img src="https://refactoring.guru/images/patterns/content/singleton/singleton.png?id=108a0b9b5ea5c4426e0afa4504491d6f">
:::success
**Why applying this design pattern?**
There's no need to create the object which contains identical method everytime
:::
#### Code sample
```typescript
/**
* The Singleton class defines the `getInstance` method that lets clients access
* the unique singleton instance.
*/
class Singleton {
private static instance: Singleton;
/**
* The Singleton's constructor should always be private to prevent direct
* construction calls with the `new` operator.
*/
private constructor() { }
/**
* The static method that controls the access to the singleton instance.
*
* This implementation let you subclass the Singleton class while keeping
* just one instance of each subclass around.
*/
public static getInstance(): Singleton {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
/**
* Finally, any singleton should define some business logic, which can be
* executed on its instance.
*/
public someBusinessLogic() {
// ...
}
}
/**
* The client code.
*/
function clientCode() {
const s1 = Singleton.getInstance();
const s2 = Singleton.getInstance();
if (s1 === s2) {
console.log('Singleton works, both variables contain the same instance.');
} else {
console.log('Singleton failed, variables contain different instances.');
}
}
clientCode();
```
log result
```
Singleton works, both variables contain the same instance.
```
<br>
---
## Apply design pattern to required on premises scenario
### module structure
api > service > component/store
```
|---apis
| |---studioApi
| |---onPremStudioApi
|---services
| |
| |--- userService
| | |---index.ts (factory + singleton)
| | |---userService.ts (strategy)
| | |---onPremUserService.ts (strategy)
| |
| |--- studioServie
| |---index.ts (factory + singleton)
| |---studioService.ts (strategy)
| |---onPremStudioService.ts (strategy)
|
|---store
|
|---view
```
### ETC (Easy to change) discussion