When to use Factory and Abstract Factory Programming Patterns

Поделиться
HTML-код
  • Опубликовано: 21 ноя 2024

Комментарии • 64

  • @git-amend
    @git-amend  Год назад +15

    24 hour challenge! See if you can find a spot in your current project where you can refactor a section of code to a Factory pattern!
    Hit the bell to keep up with new videos!

    • @stevehamilton321
      @stevehamilton321 Год назад +1

      I struggled to find a spot where I couldn't : )

  • @Lago06
    @Lago06 Год назад +9

    Thank you so much for sharing your knowledge and covering these advanced topics of game architecture and clean code! In terms of game development there are not much videos out there that target more experienced game developers (I guess mainly because the audience is much smaller). Please don't stop making them, they are very much needed and appreciated!

  • @SnowyLeopardFrom1997
    @SnowyLeopardFrom1997 4 месяца назад +2

    I never heard of this concept until 5 minutes ago. I'll need to re-watch this video

    • @git-amend
      @git-amend  4 месяца назад +1

      Sounds good, thanks for watching!

  • @Aliberation
    @Aliberation Год назад +2

    Awesome! Thank you for this lecture. For a Game Designer trying to get deeper into code like me, this is treasure. ❤

    • @git-amend
      @git-amend  Год назад +1

      Great to hear! More on the way!

  • @Broudy001
    @Broudy001 Год назад +2

    Another amazing video, I need to think about how I apply these to my game

    • @git-amend
      @git-amend  Год назад

      Awesome! I'm sure you'll find a place for a factory!

  • @gabrijel9129
    @gabrijel9129 Год назад

    Thank you a whole lot for covering these high level patterns and situations!

  • @derboss66
    @derboss66 Год назад

    Thank you very much for creating this video. After watching it, I tidied up a portion of my project :)

  • @dustintaub
    @dustintaub Год назад +1

    These are such great, advanced topics.

    • @git-amend
      @git-amend  Год назад

      Thanks! Glad you are getting a lot out of the videos!

  • @TheFlintMontana
    @TheFlintMontana 10 месяцев назад

    mate, epic video. I created a whole status effect system using this method by just passing in the equipped weapon into the Create method to define which status to use. very cool and modular and extensible!

    • @git-amend
      @git-amend  10 месяцев назад +1

      Right on, that's what I like to hear!

    • @TheFlintMontana
      @TheFlintMontana 10 месяцев назад +1

      Hi mate, One thing i did run into implementing this method (i'm still fairly beginner), is that interfaces and scriptable objects cannot implement monobehaviour. Which also means no Coroutines. I managed to find a workaround by creating a static class which you can pass a coroutine onto and it creates a single empty object to instantiate it. I was just wondering if there was any other strategies to implement monobehaviour using an abstract method like this pattern? My use example was trying to implement a burn over time with 'ticks' over the duration?
      Otherwise would a concrete abstract class that inherits scriptable objects as triggers for the effects be a better solution?
      Love your content mate, still getting across it but its the best videos of design patterns with actual unity examples i've come across! keep doing your thing.

    • @git-amend
      @git-amend  10 месяцев назад +1

      @@TheFlintMontana For me personally, I tend to roll my own timers. You'll see that in other videos, but you can also see the code here: github.com/adammyhre/3D-Platformer/blob/master/Assets/_Project/Scripts/Utils/Timer.cs
      Alternatively, there is a very good free asset you can use for Coroutines that gives you a lot more control and does not require monobehaviours: assetstore.unity.com/packages/tools/animation/more-effective-coroutines-free-54975

    • @TheFlintMontana
      @TheFlintMontana 10 месяцев назад

      amazing. Thanks mate, i'll get across it today. legend.@@git-amend

    • @TheFlintMontana
      @TheFlintMontana 10 месяцев назад

      One last question, Can you please point me in the direction of where to get Copilot integrated for unity like you have it? Cheers.@@git-amend

  • @pimor2315
    @pimor2315 Год назад +3

    Thank you for the video. I really like factory pattern. I just wonder, in the first example, you are creating factory for each weapon, like SwordFactory and BowFactory and assign one to the Soldier/Knight. Why can't we just have sword and bow as a scriptable objects and assign them directly to the knight? I find it hard to see the benefits of the factory here.

    • @git-amend
      @git-amend  Год назад +3

      Thank you for your insightful question. While it's possible to have Sword and Bow as Scriptable Objects and assign them directly, the Factory pattern introduces a layer of abstraction that allows for more complex creation logic that can be easily modified or extended - for instance, if creating a weapon involves setting up multiple parameters or state, a factory can handle this complexity in one place and you won't need a different Scriptable Object for every type of Sword or Bow in your game. In the example in the video, the Sword and Bow are very simple, but you might want your Weapon Factory to have a reference to a secondary Factory which produces a Strategy for calculating damage or for targeting. And if the Factory becomes fairly complex, I would add an internal Builder to it as well.

  • @castlecodersltd
    @castlecodersltd 3 месяца назад

    This was very helpful, thank you 🙂

    • @git-amend
      @git-amend  3 месяца назад

      You’re welcome 😊

  • @TheKr0ckeR
    @TheKr0ckeR Год назад +1

    Thanks for the great tutorial! I am always interested in "Architecture" part instead of coding after all these years in Unity and your videos are great source. Thanks for mentioning about more advanced stuffs.
    Do you prefer mono-behaviours more or focusing more on c# plain classes? For example, sword and bow are objects, and probably wont need to be a monobehaviour, but they will have mesh & etc. So do you agree with less mono-behaviour (humble-object pattern - POCO), better code or you just dont worry about it? Another example is health class, health doesnt need to be a mono behaviour since its only doing is decreasing some values etc. But when we need a healthbar, we need to create a monobehaviour to reference Image, fill amount etc. So healthbar will need Health reference to set its current / initial value etc. In tutorials, they both create health.cs and healthbar.cs as monobehaviours and healthbar references the health and subscribes events. But nowadays, Ive started to create healthbar.cs monobehaviour only, and i reference the healthbar in player, enemy etc and create health object inside player, enemy or whatever it is, and initialize healthbar.Init(health) like this. What would you have done situations like this?
    And for the next video suggestion, I would love to see how you seperate UI & Gameplay logic. For example, if we have a ShopUI.cs and buy button in it, would you do the logic inside ShopUI to buy a soldier from a SHOP? We first need to check if we can afford it, then we go soldiermanager and spawn the soldier, inside the ShopUI, or how would you approach this?

    • @git-amend
      @git-amend  Год назад +2

      Personally I tend to use C# objects as much as possible, however MonoBehaviours make life easier when you want to hook into the Unity lifecycle. Maybe I can talk about that more in the future. A few people have made similar requests to your video suggestion, so there will be a future video about that too. Cheers!

  • @hoaxygen
    @hoaxygen Год назад +1

    Excellent series

  • @shayshay8295
    @shayshay8295 10 месяцев назад

    Thanks, Love it!

    • @git-amend
      @git-amend  10 месяцев назад

      Glad you like it!

  • @TheKr0ckeR
    @TheKr0ckeR 10 месяцев назад

    As I mentioned before, I generally love using C# regular classes like you do. You have created bow, sword etc. as a plain c# class. But how would you handle what "visual" item to activate when you created Sword, or Bow. For example when we you create BOW, our character should equip the bow. So where do you handle that logic or do you give the item as direct reference to the bow class? I hope i am clear what i am asking. This is a question for how to connect visual elements with pure c# classes, and that is a great example to ask that question. How should player know we equipped the bow and it will activate the required item's etc. I generally have this difficulty when i create factories as plain class and it doesnt know what to activate, ending up complexing stuffs and corrupt the code.

    • @git-amend
      @git-amend  10 месяцев назад +2

      Well, that's more than I can answer in a comment, but will be a topic of a future video.

  • @rStarStudio
    @rStarStudio Год назад +1

    nice video!

  • @bhaktijpatil
    @bhaktijpatil 7 месяцев назад

    this was sooo helpful jesus

    • @git-amend
      @git-amend  7 месяцев назад

      Glad to hear that!

  • @zerothehero.takeasip6612
    @zerothehero.takeasip6612 Год назад

    Niiice video! Gamedev youtube rarely goes beyond the novice level so it´s nice to see design patterns applied to Unity! Question about the abstract factory though. If you have an abstract factory, which from what I understand is just having a bunch of factories grouped in one place, then what is the point of having made those individual factories to begin with? Why not just make each of the create methods within the equipment factory and you save yourself from having to add references to the original factories? It was hard to see the use from your example. I think it would be good if you could show a 2nd more complex example for each of these design patterns to see their benefit more clearly. So many programming conventions seem useless at the simple level as simpler techniques would suffice and it isn´t until you expand that you realize their use. Hence, I don´t think there is anything with how you taught it but I was left a bit unsure of the benefits of the abstract factory with the example provided.

    • @git-amend
      @git-amend  Год назад +1

      Great to hear that you found the video helpful and are interested in diving deeper! You're right; design patterns like the Abstract Factory often show their true colors when the complexity of the system increases. To address your question: The value in having separate factories and then grouping them into an abstract factory lies in modularity, separation of concerns, and ease of extension. By keeping individual factories, you can specialize them for creating particular types of objects, which may involve complex instantiation logic that is best kept isolated. An Abstract Factory serves as an orchestrator that can produce a family of related objects by composing these specialized factories.
      In a game development context, imagine you're making a multi-theme game with "Forest" and "Desert" environments. Each environment has its own types of enemies, plants, and weather conditions. By having individual factories for each category (EnemyFactory, PlantFactory, WeatherFactory), and then using a "ForestAbstractFactory" or "DesertAbstractFactory" to group them, you can easily switch between environments by simply switching the abstract factory. Each specific factory already knows how to create enemies, plants, etc., specific to its environment. So, when you decide to add a new theme like "Ocean", you can easily extend the system by creating new individual factories and a new abstract factory without touching the existing code. This makes your code more maintainable and scalable.

    • @zerothehero.takeasip6612
      @zerothehero.takeasip6612 Год назад

      ​@@git-amend I think I understand now, thank you! Though following up on your example, would it be recommendable to have the abstractEnvironmentFactories (forest, desert, and ocean) all inheret from one class that has all the factories or would you recommend another approach. I ask, cause I was curious about the organization of the elements within the factories and I know having too many inheretances can get messy quickly. Thoughts?

    • @git-amend
      @git-amend  Год назад +1

      @@zerothehero.takeasip6612 Great follow-up question! Like all engineering decisions, the answer is always, 'it depends!' Generally speaking, I would start with a base interface that your consumer class can use. For example, IEnvironmentStrategy could define methods for CreateEnemy, CreatePlant, and CreateWeather. This keeps things simple and doesn't add unnecessary layers of inheritance.
      If there are common behaviours or shared resources among all the environment factories, then having an additional base abstract class might make sense. The base class could implement some common logic and hold references to shared resources, even concrete sub-factories, if used by all types of environment factories. However, this approach does introduce an additional layer in your inheritance hierarchy, which, as you mentioned, could get messy if not managed carefully. I tend to only include an abstract base class if there are some common variables or resources needed by all concrete implementations of the interface - I start with the simplest way possible and only refactor to a higher level of complexity when the need arises. Often, you will find that once the concrete versions of your factory start to take shape, you'll find enough common elements to warrant a shared abstract class, at which point the refactoring is clear and easy to do.

    • @zerothehero.takeasip6612
      @zerothehero.takeasip6612 Год назад

      @@git-amend Thank you for the great reply, I am still trying to habitually implement these patterns into my coding. Keep up the good work!

  • @thebulletkin8393
    @thebulletkin8393 8 месяцев назад

    A very clear explanation, but I’m not sure on where this will actually be used. Putting a sword on a knight feels like something you could just assign in the editor beforehand. So would something like this just be used so that say you have a larger army in this rts style game, would it then be used to populate them with weapons at runtime?

    • @git-amend
      @git-amend  8 месяцев назад

      As your projects grow in complexity, you'll start wanting both to work from abstractions and also move more and more away from MonoBehaviour. The factory gives you the power to supply any interface, or multiple interfaces without tighlty coupling a Sword to your Player. Instead the factory determines what IWeapon to supply at run time, and that could be for all entities in your game. I forget the exact example I used, but the purpose is to decouple your game objects. If your Player just has a [SerializeField] Sword, they can only ever have a Sword. Try to see beyond the 'Weapon' example too though. You might have an ISaveSystem and a SaveSystemFactory that supplies a Json save module, but later you decide to change to Unity cloud save. You only have to change what the Factory supplies and not every single class that needs access to the save system.

  • @Forture-fm1ve
    @Forture-fm1ve 11 месяцев назад

    Thank you for your video. In your first example, can I create an abstract class 'WeaponBase' to encapsulate all common attributes and then use interfaces as you did to create different types of weapons?

    • @git-amend
      @git-amend  11 месяцев назад +1

      Absolutely. My general practice is to start with an interface, create 2-3 concrete types and at that point determine if it's worth extracting common elements into an abstract base class. Cheers!

    • @Forture-fm1ve
      @Forture-fm1ve 11 месяцев назад

      You're welcome for your answer.@@git-amend

  • @shun6284
    @shun6284 9 месяцев назад +1

    But in real project would you still use factory instead of creating the weapons or shield directly using scriptable and just assign it to the player? Like example for an item you create a Potion Scriptable Object with base class Item that has serialized properties to be customizable and just assign it to player.

    • @git-amend
      @git-amend  9 месяцев назад +2

      In a simple game assigning a Scriptable Object directly to the player is often sufficient. However, in a more complicated game you would begin to use development principles such as separation of concerns, dependency inversion and abstraction. Assigning items directly to the Player tightly couples the Player to the base class of the item, and the more tightly coupled your game is, the harder it is to make changes in the future. We'll be talking about Inventory systems in some upcoming videos.

  • @castlecodersltd
    @castlecodersltd 3 месяца назад

    I built a factory for NetworkBehaviour class that had a Builder which was working great until I tried it with more than just the host running:
    "[Netcode] Failed to create object locally. [globalObjectIdHash=0]. NetworkPrefab could not be found. Is the prefab registered with NetworkManager?"
    I was trying not to use prefabs, in my factory with Builders, but I'm guessing it's the only way to go for NetworkObjects or am I missing something (chances are high)? Or is it a case to just use a very basic GameObject with a NetworkObject attached (and registered as a prefab) and then add Components when building the object?
    Hopefully I've explained that correctly 🙂

    • @git-amend
      @git-amend  3 месяца назад +1

      With Unity's NGO, each NetworkObject must be associated with a registered prefab in the NetworkManager. This ensures that all clients in a multiplayer session can instantiate the same object consistently. When you encounter the error "[Netcode] Failed to create object locally," it typically indicates that the object you are trying to create has not been registered as a prefab in the NetworkManager.
      To solve this while still using a factory pattern, you can register a basic prefab containing a NetworkObject with the NetworkManager and then use your factory to add additional components or customize the object after instantiation. This approach allows you to maintain the flexibility of the builder pattern while satisfying the network system's requirements for synchronization across clients.

    • @castlecodersltd
      @castlecodersltd 3 месяца назад

      @@git-amend thank you, that's what I ended up going with. All the best 🙂

  • @yeric17
    @yeric17 11 месяцев назад

    ¡Gracias!

    • @git-amend
      @git-amend  11 месяцев назад

      Wow thank you!

    • @yeric17
      @yeric17 11 месяцев назад

      @@git-amend Your content is of great quality, your videos are impressive.

  • @laserbean00001
    @laserbean00001 Год назад

    Love your anime art clickbaits

  • @umoyGC
    @umoyGC Год назад

    Hi Adam, I wonder if there is a possiblity in using this factory pattern for switching skinned mesh renderer "objects".
    I wanted to change Armor parts of a sinty studios model. my code is working so far but it is a giant mess of swich cases if the part is an arm or the helmet and so on. What do you think can be a good approach to that? Also using interfaces for the body parts or have you a better or "smoother" idea :)
    Thanks in advance for reading my comment :)

    • @git-amend
      @git-amend  Год назад +3

      Great comment, and perhaps a great topic for a future video, as I know this is a pain point for many people. While the Factory pattern is useful for creating objects, a more suitable pattern for this scenario could be the Strategy pattern. Here's a brief overview:
      The Strategy pattern is used to define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from objects that use it. In this context, each type of armor part (helmet, arm, etc.) could be treated as a strategy. You can create an interface, say IArmorPart, with a method like ApplyPart() or ChangePart(). Then, implement this interface in different classes representing different armor parts.
      This approach will remove the need for switch cases and will make the code more organized. Each armor part's behaviour is encapsulated in its respective class.
      You could still use a Factory to create your various Weapons and Armor, but when creating them, you also provide each with an appropriate Strategy that will contain the logic for applying themselves to your character(s). Small example:
      public interface IArmorPart {
      void ApplyPart(GameObject character);
      }
      public class PlayerEquipment : MonoBehaviour {
      public IArmorPart currentArmorPart;
      // or maybe Dictionary equipment;
      public void ChangeArmorPart(IArmorPart newArmorPart) {
      currentArmorPart = newArmorPart;
      currentArmorPart.ApplyPart(gameObject);
      }
      }
      [CreateAssetMenu(...)]
      public class HelmetPlacementStrategy : ScriptableObject, IArmorPart {
      public Mesh helmetMesh;
      public Material helmetMaterial;
      public void ApplyPart(GameObject character) {
      // Logic to actually change the armor on the character.
      // For example, find the helmet mesh renderer and apply the new mesh and material,
      // or activate/deactivate GameObjects.
      }
      }
      This way your various strategies determine what happens when you 'Apply' them to your character, and not a huge list of conditional statements. Hope that helps give you some ideas!

    • @umoyGC
      @umoyGC Год назад +1

      Many thx for this amazing fast and detailed answer. I will track the video about strategy patterns and will try my best to update my code in a clean and efficient way. Thank you so much :) @@git-amend

  • @pliniojrm
    @pliniojrm 2 месяца назад

    Your Unity runs so fast when hitting play. It does not try to recompile everytime.
    Or is it you/editor that cut that part out so the video is smooth to what it matters?

    • @git-amend
      @git-amend  2 месяца назад +1

      Generally I edit out the boring parts, but I also have domain reload turned off so I only refresh when it's necessary. And more recently I've been using Hot Reload which is even faster.