Langsung ke konten utama

Factory Method: Problem -> Solution -> Results 🚀

 

Factory Method: Problem -> Solution -> Results 🚀

Alright, let's dive into this pattern.


 

The Problem 🤔

Imagine you're building an app, maybe a game where players can choose different types of characters (like Warriors, Mages, Archers). At first, you might just create them directly wherever you need them, like:

// Somewhere in your game logic...
Character player1 = new Warrior();
Character player2 = new Mage();

This works fine for a small game. But what happens when you add tons of character types? Or maybe the way you create characters gets super complex, needing specific stats or items? Your main code gets cluttered with all this character creation logic.

Even worse, if you decide to change how a Warrior is created (maybe they need a specific starting weapon now), you have to hunt down every single place you created a Warrior and change it. Major headache! 😩 It makes your code rigid and hard to update. You're basically locked into the specific classes you're creating directly.

The Solution ✨ (The Factory Method!)

Definition: The Factory Method is a creational design pattern that provides an interface (like a blueprint) for creating objects in a parent class, but lets the child classes decide which specific object to actually create. Think of it as delegating the "which one to make" decision downstairs.

The Factory Method is like having a dedicated "Character Creator" machine. Instead of building characters directly in your main game logic, you ask this machine (the "Factory") to make one for you.

Here's the gist with some code snippets:

  1. Define an Interface/Abstract Class (The Product): Create a blueprint for what you're making.

    // The common blueprint for all characters
    interface Character {
        void displayInfo();
    }
    
  2. Concrete Classes (Concrete Products): Create the specific versions.

    // Specific character types implementing the blueprint
    class Warrior implements Character {
        public void displayInfo() { /* Warrior details */ }
    }
    class Mage implements Character {
        public void displayInfo() { /* Mage details */ }
    }
    
  3. Creator Class (The Abstract Factory): Declares the magic factoryMethod() that subclasses will use.

    // Declares the method to create a Character, but doesn't implement it
    abstract class CharacterFactory {
        // This is the Factory Method!
        public abstract Character createCharacter();
    
        // Optional: Other methods that use the created character
        public void someOperation() {
            Character character = createCharacter(); // Uses the factory method
            // ... do something with the character ...
        }
    }
    
  4. Concrete Creators (The Specific Factories): These guys actually do the creating for a specific type.

    // Implements the factory method to create a *specific* character
    class WarriorFactory extends CharacterFactory {
        @Override
        public Character createCharacter() {
            return new Warrior(); // Creates and returns a Warrior
        }
    }
    class MageFactory extends CharacterFactory {
        @Override
        public Character createCharacter() {
            return new Mage(); // Creates and returns a Mage
        }
    }
    

Now, your main game logic doesn't need to know how to create a Warrior or Mage. It just talks to a CharacterFactory and says, "Yo, gimme a character!" The specific factory takes care of the messy details.

// Main game logic only knows about the factory
CharacterFactory factory = new WarriorFactory(); // Or new MageFactory();
Character player1 = factory.createCharacter(); // Factory handles the 'new Warrior()' part! ✨
player1.displayInfo();

CharacterFactory anotherFactory = new MageFactory();
Character player2 = anotherFactory.createCharacter(); // Factory handles the 'new Mage()' part! ✨
player2.displayInfo();

The Results 😎

Using the Factory Method gives you some sweet benefits:

  1. Flexibility: Wanna add a new character type, like Ninja? Just create a Ninja class and a NinjaFactory. Your main game code doesn't need to change much, if at all! It just needs to be able to use the new factory. Super adaptable.

  2. Cleaner Code (Decoupling): Your main logic isn't tangled up with how objects are created. It just cares about using the objects. The creation part is neatly tucked away in the factories. This makes your code easier to read, test, and maintain. ✨

  3. Centralized Control: All the logic for creating a specific type of object (like a Warrior) lives inside its corresponding factory (WarriorFactory). Need to change how Warriors are made? You only edit it in one place. Easy peasy.

  4. Open/Closed Principle: Your core game logic is "closed" for modification (you don't need to change it often) but "open" for extension (you can easily add new character types and factories).

Basically, it makes your code less messy, more organized, and way easier to expand without breaking everything. It's all about letting subclasses decide which specific class to create.

Komentar

Postingan populer dari blog ini

Pembuatan Software Pasti Mengalami Keterlambatan!!!

Yes, Anda tidak salah membaca judul atau mendengar. Saya yakin ketika Anda membuat project secara pribadi ataupun untuk orang lain, client, dan team internal pasti mengalami keterlambatan. Selama menjadi software engineer, saya masih mencari tau alasan mengapa pembuatan software menjadi terlambat.  Oh mungkin karena teamnya kurang kompeten,  Oh munkin timelinenya kurang panjang,  Oh mungkin permintaan yang berubah-rubah di tengah jalan,  Oh mungkin standarisasinya yang kurang baik di terapkan,  Oh mungkin dari awal permintaannya kurang jelas,  dan masih banyak lagi... Sebab musabab diatas hanyalah sedikit dari banyak sebab yang sering saya dengar atau bahkan yang saya ikut terjun didalamnnya. Tapi apakah pembuatan software ngak bisa ontime? jawabannya Bisa, ujar seorang software engineer yang di anggap senior, dan di kenyataannya tidak sesimple kalimat Bisa. Kalimat Bisa sering saya dapatkan ketika client yang minta dan software engineer yang jawab atau jik...

Laravel Best Practices: The Pragmatic Guide

  Laravel Best Practices: The Pragmatic Guide Mengapa Best Practices Penting dalam Pengembangan Laravel? Dalam dunia pengembangan web yang serba cepat, kita sebagai developer Laravel sering terjebak dalam siklus "yang penting jadi". Aplikasi berjalan? Check. Fitur berfungsi? Check. Tapi tunggu dulu—bagaimana dengan kualitas kode, maintainability, dan skalabilitas jangka panjang? Laravel memang menawarkan ekosistem yang elegan, tetapi tanpa penerapan best practices, kita bisa berakhir dengan "utang teknis" yang menumpuk. Mari kita bahas panduan pragmatis yang akan mengubah cara Anda mengembangkan aplikasi Laravel. Prinsip Single Responsibility Salah satu kesalahan umum yang sering terjadi adalah membuat "Fat Controller"—controller yang melakukan terlalu banyak hal. Controller seharusnya hanya bertanggung jawab untuk mengkoordinasikan permintaan , bukan menangani logika bisnis. Bandingkan kode berikut: // Cara yang kurang baik public function store(Re...