<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tu Bui</title>
    <description>The latest articles on DEV Community by Tu Bui (@t_bi_a6d385ba2e05d3d128).</description>
    <link>https://dev.to/t_bi_a6d385ba2e05d3d128</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1842468%2F546ed9be-117c-414b-854a-b54cea825952.png</url>
      <title>DEV Community: Tu Bui</title>
      <link>https://dev.to/t_bi_a6d385ba2e05d3d128</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/t_bi_a6d385ba2e05d3d128"/>
    <language>en</language>
    <item>
      <title>Setup new project slot</title>
      <dc:creator>Tu Bui</dc:creator>
      <pubDate>Mon, 05 May 2025 03:56:44 +0000</pubDate>
      <link>https://dev.to/t_bi_a6d385ba2e05d3d128/setup-new-project-slot-b0p</link>
      <guid>https://dev.to/t_bi_a6d385ba2e05d3d128/setup-new-project-slot-b0p</guid>
      <description>&lt;h2&gt;
  
  
  Setup doc-slot-core
&lt;/h2&gt;

&lt;p&gt;1.Clone project and open with VSCode: &lt;a href="https://gitea.plp19.com/dev-public/doc-slot-core-manual" rel="noopener noreferrer"&gt;https://gitea.plp19.com/dev-public/doc-slot-core-manual&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install
npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.Setup follow README&lt;br&gt;
You can read doc at link: &lt;a href="http://localhost:3000/docs/intro" rel="noopener noreferrer"&gt;http://localhost:3000/docs/intro&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup project
&lt;/h2&gt;
&lt;h2&gt;
  
  
  NOTE:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;When setup list SlotttyItem, these Items in this game is difference with doc:
['WILD', 'PIC1', 'PIC2', 'PIC3', 'PIC4', 'PIC5', 'ACE', 'KING', 'QUEEN', 'JACK', 'TEN', 'NINE', 'COLLECT', 'SCAT']&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So these script have to update:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;extend-slotty-setting.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var SlottyItem = p4fslot.require('slotty-item');
var Enum = p4fslot.require('extendable-enum');

Enum.InitEnum(SlottyItem, [
    'Pic1',
    'Pic2',
    'Pic3',
    'Pic4',
    'Pic5',
    'Ace',
    'King',
    'Queen',
    'Jack',
    'Ten',
    'Nine',
    'Collect',
]);

module.exports = SlottyItem;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;extend-hyper-gaming-config.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var HyperGamingConfig = require('hyper-gaming-config');
var SlottyItem = require('slotty-item');

HyperGamingConfig.itemMapper['PIC1'] = SlottyItem.Pic1;
HyperGamingConfig.itemMapper['PIC2'] = SlottyItem.Pic2;
HyperGamingConfig.itemMapper['PIC3'] = SlottyItem.Pic3;
HyperGamingConfig.itemMapper['PIC4'] = SlottyItem.Pic4;
HyperGamingConfig.itemMapper['PIC5'] = SlottyItem.Pic5;
HyperGamingConfig.itemMapper['ACE'] = SlottyItem.Ace;
HyperGamingConfig.itemMapper['KING'] = SlottyItem.King;
HyperGamingConfig.itemMapper['QUEEN'] = SlottyItem.Queen;
HyperGamingConfig.itemMapper['JACK'] = SlottyItem.Jack;
HyperGamingConfig.itemMapper['TEN'] = SlottyItem.Ten;
HyperGamingConfig.itemMapper['NINE'] = SlottyItem.Nine;
HyperGamingConfig.itemMapper['COLLECT'] = SlottyItem.Collect;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;extend-slotty-setting.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
BaseSlottySetting.prototype._getPatternNotWin = function () {
    return [
        [SlottyItem.Pic5, SlottyItem.Pic3, SlottyItem.Pic5, SlottyItem.Pic1, SlottyItem.Pic5,
        SlottyItem.Pic2, SlottyItem.Pic6, SlottyItem.Pic5, SlottyItem.Pic1, SlottyItem.Pic5,
        SlottyItem.Pic2, SlottyItem.Pic6, SlottyItem.Pic2, SlottyItem.Pic1, SlottyItem.Pic2
        ],
        [SlottyItem.Pic4, SlottyItem.Pic7, SlottyItem.Pic2, SlottyItem.Pic5, SlottyItem.Pic7,
        SlottyItem.Pic4, SlottyItem.Pic7, SlottyItem.Pic6, SlottyItem.Pic5, SlottyItem.Pic7,
        SlottyItem.Pic7, SlottyItem.Pic3, SlottyItem.Pic4, SlottyItem.Pic2, SlottyItem.Pic3
        ],
        [SlottyItem.Pic1, SlottyItem.Pic2, SlottyItem.Pic3, SlottyItem.Pic7, SlottyItem.Pic3,
        SlottyItem.Pic2, SlottyItem.Pic7, SlottyItem.Pic4, SlottyItem.Pic3, SlottyItem.Pic2,
        SlottyItem.Pic1, SlottyItem.Pic7, SlottyItem.Pic4, SlottyItem.Pic3, SlottyItem.Pic1
        ]
    ];
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Update Asset &amp;amp; Folder Structure:
&lt;/h2&gt;

&lt;p&gt;When add asset to folder structure. Remember to run 4 things:&lt;br&gt;
_Open Preload Scene: P4F Editor -&amp;gt; preload-hyper -&amp;gt; loadAll&lt;br&gt;
_3 step in this image:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2h6rnkw2sdo61kjqokj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2h6rnkw2sdo61kjqokj3.png" alt="Image description" width="371" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>CC Pool</title>
      <dc:creator>Tu Bui</dc:creator>
      <pubDate>Fri, 14 Mar 2025 07:31:22 +0000</pubDate>
      <link>https://dev.to/t_bi_a6d385ba2e05d3d128/cc-pool-38fh</link>
      <guid>https://dev.to/t_bi_a6d385ba2e05d3d128/cc-pool-38fh</guid>
      <description>&lt;p&gt;&lt;a href="https://docs.cocos.com/creator/2.4/manual/en/scripting/pooling.html" rel="noopener noreferrer"&gt;https://docs.cocos.com/creator/2.4/manual/en/scripting/pooling.html&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onLoad: function () {
    this.enemyPool = new cc.NodePool();
    let initCount = 5;
    for (let i = 0; i &amp;lt; initCount; ++i) {
        let enemy = cc.instantiate(this.enemyPrefab); // create node instance
        this.enemyPool.put(enemy); // populate your pool with put method
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;createEnemy: function (parentNode) {
    let enemy = null;
    if (this.enemyPool.size() &amp;gt; 0) { // use size method to check if there're nodes available in the pool
        enemy = this.enemyPool.get();
    } else { // if not enough node in the pool, we call cc.instantiate to create node
        enemy = cc.instantiate(this.enemyPrefab);
    }
    enemy.parent = parentNode; // add new enemy node to the node tree
    enemy.getComponent('Enemy').init(); //initialize enemy
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onEnemyKilled: function (enemy) {
    // enemy should be a cc.Node instance
    this.enemyPool.put(enemy); // using the same put method as initializing node pool, this will also call removeFromParent for the node
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Facade Pattern</title>
      <dc:creator>Tu Bui</dc:creator>
      <pubDate>Thu, 13 Mar 2025 07:03:06 +0000</pubDate>
      <link>https://dev.to/t_bi_a6d385ba2e05d3d128/facade-pattern-286h</link>
      <guid>https://dev.to/t_bi_a6d385ba2e05d3d128/facade-pattern-286h</guid>
      <description>&lt;p&gt;&lt;a href="https://refactoring.guru/design-patterns/facade" rel="noopener noreferrer"&gt;https://refactoring.guru/design-patterns/facade&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Target: Avoid call many function from something or package.&lt;br&gt;
A facade is a class that provides a simple interface to a complex subsystem which contains lots of moving parts. A facade might provide limited functionality in comparison to working with the subsystem directly. However, it includes only those features that clients really care about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;br&gt;
When you want to order pizza. Just call to the operator who provide you all function of shop like order, payment, delivery,...&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface IGameFacade {
    startGame(): void;
    pauseGame(): void;
    endGame(): void;
}

class GameFacade implements IGameFacade {
    private physicsSystem: PhysicsSystem;
    private uiManager: UIManager;

    constructor() {
        this.physicsSystem = new PhysicsSystem();
        this.uiManager = new UIManager();
    }

    startGame() {
        this.physicsSystem.enable();
        this.uiManager.showGameUI();
        console.log("Game started!");
    }

    pauseGame() {
        this.physicsSystem.disable();
        this.uiManager.showPauseMenu();
        console.log("Game paused.");
    }

    endGame() {
        this.physicsSystem.reset();
        this.uiManager.showEndScreen();
        console.log("Game ended.");
    }
}

class PhysicsSystem {
    enable() { console.log("Physics enabled"); }
    disable() { console.log("Physics disabled"); }
    reset() { console.log("Physics reset"); }
}

class UIManager {
    showGameUI() { console.log("Game UI shown"); }
    showPauseMenu() { console.log("Pause menu shown"); }
    showEndScreen() { console.log("End screen shown"); }
}

// Usage
const game = new GameFacade();
game.startGame();
game.pauseGame();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>GSAP TWEEN</title>
      <dc:creator>Tu Bui</dc:creator>
      <pubDate>Thu, 13 Mar 2025 07:01:19 +0000</pubDate>
      <link>https://dev.to/t_bi_a6d385ba2e05d3d128/gsap-tween-1hon</link>
      <guid>https://dev.to/t_bi_a6d385ba2e05d3d128/gsap-tween-1hon</guid>
      <description>&lt;p&gt;//Declare Timeline&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private timeLineMove: gsap.core.Timeline;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;//CreateTimeline&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private tweenScaleThenTrasparent(): void
    {
        this.timeLine = gsap.timeline({ paused: true });
        timeLine.fromTo(this.node,{scaleX: 1},{
            scaleX: 1.1,
            duration: 0.2
        }, "scaleUp");
        timeLine.fromTo(this.node,{scaleX: 1.1},{
            scaleX: 1,
            duration: 0.2
        }, "scaleDown");
        timeLine.fromTo(this.node,{opacity: 255},{
            opacity: 0,
            duration: 0.2
            ease: Back.easeOut
        }, "transparent");
    }
//Using
this.timeline.restart();
//MUST
protected onDestroy(): void
{
   if (this.timeLineMoveUp)
   {
       this.timeLineMoveUp.kill();
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice:&lt;br&gt;
_Create Timeline moving to X = 100;&lt;br&gt;
_First time moving from 0=&amp;gt;100&lt;br&gt;
_When use timeLineMove.restart(); if current x = -500 =&amp;gt; Tween still move from 0-&amp;gt;100&lt;/p&gt;

</description>
    </item>
    <item>
      <title>NPM SETUP</title>
      <dc:creator>Tu Bui</dc:creator>
      <pubDate>Fri, 20 Sep 2024 08:38:51 +0000</pubDate>
      <link>https://dev.to/t_bi_a6d385ba2e05d3d128/npm-setup-34bo</link>
      <guid>https://dev.to/t_bi_a6d385ba2e05d3d128/npm-setup-34bo</guid>
      <description>&lt;p&gt;Step 1: Install Node.js in this link &lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;br&gt;
This automatic help you install npm&lt;br&gt;
Step 2: After install Node.js test in terminal &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiz49fvgbpf90rk9nqiyh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiz49fvgbpf90rk9nqiyh.png" alt="Image description" width="497" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: &lt;br&gt;
If have some problem acn't access to npm , node ,...&lt;br&gt;
Delete C:\Users&amp;lt;accountName&amp;gt;\AppData\Roaming\npm&lt;br&gt;
Uninstall nodejs &amp;amp; reinstall. &lt;/p&gt;

</description>
      <category>npm</category>
      <category>typescript</category>
      <category>tsc</category>
    </item>
    <item>
      <title>Inversify Inject Decoration</title>
      <dc:creator>Tu Bui</dc:creator>
      <pubDate>Wed, 31 Jul 2024 10:21:45 +0000</pubDate>
      <link>https://dev.to/t_bi_a6d385ba2e05d3d128/inversify-inject-decoration-2obn</link>
      <guid>https://dev.to/t_bi_a6d385ba2e05d3d128/inversify-inject-decoration-2obn</guid>
      <description>&lt;p&gt;I'm already using Inversify in Cocos project. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Performance Optimization&lt;/strong&gt;&lt;br&gt;
_ &lt;strong&gt;Lazy Loading:&lt;/strong&gt; lazyInject allows for lazy loading of dependencies, which means thay are only instantiated when they are actually needed. This can significantly improve the performance of your application, especially if some dependencies are expensive to create and might not be used in every execution path.&lt;br&gt;
_ &lt;strong&gt;Reduced Initialization Time:&lt;/strong&gt; By deferring the creation of dependencies until they are accessed, the initial loading time of the application can be reduced.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Memory Management&lt;/strong&gt;&lt;br&gt;
_ &lt;strong&gt;Efficient Use of Resources:&lt;/strong&gt; Since dependencies are only created when required, it helps in better memory management and resource utilization. This can be particularly useful in applications with large numbers of dependencies or those that run in environments with limited resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Circular Dependency Resolution&lt;/strong&gt;&lt;br&gt;
_ &lt;strong&gt;Avoid Circular Dependencies:&lt;/strong&gt; lazyInject can help in resolving circular dependencies by delaying the injection until the dependencies are actually needed. This can prevent issues where two or more services depend on each other, causing a circular dependency error during initialization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Better Control and Flexibility&lt;/strong&gt;&lt;br&gt;
_ &lt;strong&gt;Fine-Grained Control:&lt;/strong&gt; With lazyInject, developers have more control over when and how dependencies are instantiated. This can lead to better optimization and flexibility in managing dependencies.&lt;br&gt;
_ &lt;strong&gt;Conditional Instantiation:&lt;/strong&gt; It allows for conditional instantiation of dependencies based on runtime conditions, which can lead to more efficient and context-aware dependency management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Best Practices in Dependency Injection&lt;/strong&gt;&lt;br&gt;
_ &lt;strong&gt;Adherence to SOLID Principles:&lt;/strong&gt; Using lazyInject aligns the Dependency Inversion Principle (DIP) and the Single Responsibility Principle (SRP), both of which are part of the SOLID principles of object-oriented design. It ensures that classes depend on abstractions rather than concrete implementations and that they are only responsible for their primary functionality.&lt;br&gt;
_ &lt;strong&gt;Separation of Concerns:&lt;/strong&gt; By using lazyInject, you maintain a clear separation of concerns. The class that depends on a service doesn't need to know how to create it, only how to use it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { injectable, inject } from "inversify";
import { lazyInject } from "inversify/lib/annotation/lazy_inject";

@injectable()
class SomeService {
    // ...
}

@injectable()
class AnotherService {
    @lazyInject(TYPES.SomeService)
    private someService: SomeService;

    public doSomething() {
        this.someService.someMethod();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>typescript</category>
      <category>inversify</category>
      <category>lazyinject</category>
      <category>decoration</category>
    </item>
    <item>
      <title>Reflect MetaData</title>
      <dc:creator>Tu Bui</dc:creator>
      <pubDate>Tue, 30 Jul 2024 08:15:44 +0000</pubDate>
      <link>https://dev.to/t_bi_a6d385ba2e05d3d128/reflect-metadata-2ie5</link>
      <guid>https://dev.to/t_bi_a6d385ba2e05d3d128/reflect-metadata-2ie5</guid>
      <description>&lt;p&gt;_When your project is getting bigger and bigger.&lt;br&gt;
Some solution to fix it is _Composition/Dependency Injection, Run-time Type Assertions, Testing, Decoration,... So a consistent approach is needed for various tools and libraries to be able to reason over metadata.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In my case, I'm trying to use Inversify package. It's require to use ReflectMetaData Package.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;_Inversify is an Inversion of Control(IoC) container for TypeScript &amp;amp; TypeScript. It helps manage dependencies in applications. It uses decorators to mark classes and their dependencies, promoting modular, testable, and maintainable code.&lt;/p&gt;

&lt;p&gt;_Reflect-Metadata&lt;br&gt;
The reflect-metadata package adds a reflection API to JavaScript, which is used to add and retrieve metadata to/from JavaScript objects at runtime. In TypeScript, this allows the storage of type information and other metadata.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connection&lt;br&gt;
Decorators and Metadata:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Inversify relies on decorators to mark classes (@injectable) and their dependencies (@inject).&lt;br&gt;
TypeScript decorators, in combination with reflect-metadata, enable the retrieval of type information at runtime. This is essential for Inversify to automatically inject the correct dependencies based on type information.&lt;br&gt;
Automatic Dependency Resolution:&lt;/p&gt;

&lt;p&gt;When you mark a class with @injectable, Inversify uses reflect-metadata to store metadata about the class and its constructor parameters.&lt;br&gt;
When you use the @inject decorator, Inversify retrieves the type metadata for the constructor parameters, which allows the container to resolve and inject the appropriate instances automatically.&lt;/p&gt;

</description>
      <category>npm</category>
      <category>reflect</category>
      <category>metadata</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Inversify</title>
      <dc:creator>Tu Bui</dc:creator>
      <pubDate>Tue, 30 Jul 2024 03:27:36 +0000</pubDate>
      <link>https://dev.to/t_bi_a6d385ba2e05d3d128/ioc-1m74</link>
      <guid>https://dev.to/t_bi_a6d385ba2e05d3d128/ioc-1m74</guid>
      <description>&lt;p&gt;This is good example for you to easy understand how inversify work.&lt;/p&gt;

&lt;p&gt;I will improve code follow each step below:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Normal Class&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Cart
{
    private readonly IDatabase _db;
    private readonly ILogger _log;
    private readonly IEmailSender _es;

    public Cart()
    {
        _db = new Database();
        _log = new Logger();
        _es = new EmailSender();
    }

    public void Checkout(int orderId, int userId)
    {
        _db.Save(orderId);
        _log.LogInfo("Order has been checkout");
        _es.SendEmail(userId);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2:Apply Dependency Injection&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public Cart(IDatabase db, ILogger log, IEmailSender es)
{
        _db = db;
        _log = log;
        _es = es;
 }

 //Dependency Injection simple way
 Cart myCart = new Cart(new Database(),
                   new Logger(), new EmailSender());
 //When you want to change new class. Update here
 myCart = new Cart(new XMLDatabase(),
              new FakeLogger(), new FakeEmailSender());
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Apply dependency-graph-binding&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Create each Interface
DIContainer.SetModule&amp;lt;IDatabase, Database&amp;gt;();
DIContainer.SetModule&amp;lt;ILogger, Logger&amp;gt;();
DIContainer.SetModule&amp;lt;IEmailSender, EmailSender&amp;gt;();

DIContainer.SetModule&amp;lt;Cart, Cart&amp;gt;();

//MyCart just need to use it
var myCart = DIContainer.GetModule(); 
public Cart()
    {
        _db = DIContainer.GetModule();
        _log = DIContainer.GetModule();
        _es = DIContainer.GetModule();
    }

//When you want to change some module in Cart. Just need to change in where it define.
DIContainer.SetModule&amp;lt;IDatabase, XMLDatabase&amp;gt;();`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>inversify</category>
      <category>npm</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Safely restructure your codebase with Dependency Graphs</title>
      <dc:creator>Tu Bui</dc:creator>
      <pubDate>Mon, 29 Jul 2024 04:10:29 +0000</pubDate>
      <link>https://dev.to/t_bi_a6d385ba2e05d3d128/safely-restructure-your-codebase-with-dependency-graphs-3596</link>
      <guid>https://dev.to/t_bi_a6d385ba2e05d3d128/safely-restructure-your-codebase-with-dependency-graphs-3596</guid>
      <description>&lt;p&gt;Using "inversify" is a key to create Deoencency-Graph-Binding&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Container } from "inversify";

var container = new Container();
export { container };

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { interfaces, namedConstraint, taggedConstraint, traverseAncerstors, typeConstraint } from "inversify";

class BindingHelper
{
    targetNamed(request: interfaces.Request, name: string | number | symbol): boolean
    {
        return request != null &amp;amp;&amp;amp; request.target.matchesNamedTag(name.toString());
    }

    targetTagged(request: interfaces.Request, key: string | number | symbol, value: unknown): boolean
    {
        return request != null &amp;amp;&amp;amp; request.target.matchesTag(key)(value);
    }

    targetIsDefault(request: interfaces.Request): boolean
    {
        return request != null &amp;amp;&amp;amp; request.target != null &amp;amp;&amp;amp; !request.target.isNamed() &amp;amp;&amp;amp; !request.target.isTagged();
    }

    injectInto(request: interfaces.Request, parent: (NewableFunction | string)): boolean
    {
        return request != null &amp;amp;&amp;amp; typeConstraint(parent)(request.parentRequest);
    }

    parentNamed(request: interfaces.Request, name: string | number | symbol): boolean
    {
        return request != null &amp;amp;&amp;amp; namedConstraint(parent)(request.parentRequest);
    }

    parentTagged(request: interfaces.Request, tag: string | number | symbol, value: unknown): boolean
    {
        return request != null &amp;amp;&amp;amp; taggedConstraint(tag)(value)(request.parentRequest);
    }

    anyAncestorIs(request: interfaces.Request, ancestor: (NewableFunction | string)): boolean
    {
        return traverseAncerstors(request, typeConstraint(ancestor));
    }

    noAncestorIs(request: interfaces.Request, ancestor: (NewableFunction | string)): boolean
    {
        return !traverseAncerstors(request, typeConstraint(ancestor));
    }

    anyAncestorTagged(request: interfaces.Request, tag: string | number | symbol, value: unknown): boolean
    {
        return traverseAncerstors(request, taggedConstraint(tag)(value));
    }

    noAncestorTagged(request: interfaces.Request, tag: string | number | symbol, value: unknown): boolean
    {
        return !traverseAncerstors(request, taggedConstraint(tag)(value));
    }

    anyAncestorNamed(request: interfaces.Request, name: string | number | symbol): boolean
    {
        return traverseAncerstors(request, namedConstraint(name));
    }

    noAncestorNamed(request: interfaces.Request, name: string | number | symbol): boolean
    {
        return !traverseAncerstors(request, namedConstraint(name));
    }
}

var when = new BindingHelper();
export { when };

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Container, interfaces } from "inversify";
import { when } from "./context-binding-helper";


interface DependencyBranch
{
    from(type: any): DependencyGraphHelper;
}

class DependencyGraphHelper implements DependencyBranch
{
    private container: Container;
    private graphs: any[] = [];
    private isBranching: boolean;
    private branchNode: any;

    bind(identifier: any, type: any, isConstant: boolean = false): DependencyGraphHelper
    {
        if (this.isBranching)
        {
            console.error('Please specify which class to be branched from. Parameters: ', identifier, ' ', type);
        }
        var parent = this.graphs[this.graphs.length - 1];
        var node = { identifier: identifier, type: type, parent: parent, isConstant: isConstant };
        this.graphs.push(node);
        return this;
    }

    branch(identifier: any, type: any, isConstant: boolean = false): DependencyBranch
    {
        if (this.graphs.length == 0)
        {
            console.error('Dependency graph cannot start with a "branch". It must start with a "bind" function.Parameters: ', identifier, ' ', type);
        }
        if (this.isBranching)
        {
            console.error('Please specify which class to be branched from. Parameters: ', identifier, ' ', type);
        }
        this.isBranching = true;
        this.branchNode = { identifier: identifier, type: type, isConstant: isConstant };
        return this;
    }

    from(type: any): DependencyGraphHelper
    {
        if (this.isBranching == false)
        {
            console.error('A "from" function must be called after a "branch" function. Parameters: ', type);
        }
        this.isBranching = false;
        var parent = this.graphs.filter(i =&amp;gt; i.type == type).pop();
        this.branchNode.parent = parent;
        this.graphs.push(this.branchNode);
        return this;
    }

    registerTo(container: Container): void
    {
        if (this.isBranching)
        {
            console.error('Please specify which class to be branched from before call "register" function.');
        }
        this.container = container;
        for (let index = 0; index &amp;lt; this.graphs.length; index++)
        {
            const graph = this.graphs[index];
            this.registerGraph(graph);
        }
        this.graphs = [];
        this.container = null;
    }

    private registerGraph(graph: any): void
    {
        if (graph.isConstant)
        {
            this.bindToConstant(graph);
        }
        else
        {
            this.bindTo(graph);
        }
    }

    private bindTo(graph: any): void
    {
        this.container.bind(graph.identifier).to(graph.type).when(request =&amp;gt;
        {
            return this.recursiveCheckBindingCondition(request, graph);
        });
    }

    private bindToConstant(graph: any): void
    {
        this.container.bind(graph.identifier).toConstantValue(graph.type).when(request =&amp;gt;
        {
            return this.recursiveCheckBindingCondition(request, graph);
        });
    }

    private recursiveCheckBindingCondition(request: interfaces.Request, graph: any): boolean
    {
        if (graph.parent == null)
        {
            return true;
        }
        var injected = when.injectInto(request, graph.parent.type) &amp;amp;&amp;amp; this.recursiveCheckBindingCondition(request.parentRequest, graph.parent);
        return injected;
    }
}

var dependencyGraph = new DependencyGraphHelper();
export { dependencyGraph };


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { dependencyGraph } from "../../common/ioc-helper/dependency-graph-helper";
import { container } from "../../ioc/ioc-container";
import { MonkeyClimb } from "../monkey/monkey-climb";
import { MonkeyControl } from "../monkey/monkey-control";
import { MonkeyEat } from "../monkey/monkey-eat";
import { MonkeyFindFood } from "../monkey/monkey-find-food";
import { MonkeySwingThroughTheTree } from "../monkey/monkey-swing-through-the-tree";
import { MONKEY } from "./animal-ioc-config";

export default class DependenceGraphBinding
{
    public register(): void
    {
        this.registerMonkey();
    }

    private registerMonkey(): void
    {
        dependencyGraph
            .bind(MONKEY.CONTROL,MonkeyControl)
                .branch(MONKEY.EAT,MonkeyEat).from(MonkeyControl)
                .branch(MONKEY.FIND_FOOD,MonkeyFindFood).from(MonkeyControl)
                    .branch(MONKEY.FIND_FOOD,MonkeyClimb).from(MonkeyFindFood)
                    .branch(MONKEY.FIND_FOOD,MonkeySwingThroughTheTree).from(MonkeyFindFood)
            .registerTo(container);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>typescript</category>
      <category>dependency</category>
      <category>graph</category>
      <category>binding</category>
    </item>
  </channel>
</rss>
