Jump to content
  • Advertisement
SvetlanaRosemond

Java Using the Strategy Pattern to avoid downcasting

Recommended Posts

I was reading on this site about the Liskov substitution principle. It states:

Quote

As per the LSP, functions that use references to base classes must be able to use objects of the derived class without knowing it. In simple words, derived classes must be substitutable for the base class.

From my understanding this means that whatever methods are in my base class, they must be implemented in my subclass, and according to this page, if you override a method in the base class and it does nothing or throws an exception, you're in violation of the principle.

Suppose I had an abstract class called Weapon, and the subclasses ReloadableWeapon and Sword. ReloadableWeapon contains a method that's unique to that class, called Reload(). When declaring objects, standard practice is you do it from the abstract class and then subclass, like so:

Weapon rifle = new ReloadableWeapon(); 
Weapon sword = new Sword();

If I wanted to use the reload method for a rifle, I could cast it. Based on numerous articles and textbooks, this could lead to problems later on.

Also, if I have the reload method in the base class Weapon, then Sword would ignore or throw, which is wrong.

If I wanted to avoid all that, would using the Strategy Pattern be a viable option?
 

public final Weapon{

    private final String name;
    private final int damage;
    private final List<AttackStrategy> validactions;
    private final List<Actions> standardActions;

    private Weapon(String name, int damage, List<AttackStrategy> standardActions, List<Actions> attacks)
    {
        this.name = name;
        this.damage = damage;
        standardActions = new ArrayList<Actions>(standardActions);
        validAttacks = new ArrayList<AttackStrategy>(validActions);
    }

    public int attack(String action){} // - Call any actions that are attacks.

    public void standardAction(String action){} // - Call aim or reload here.
    
    public static Weapon Sword(final String name, final damage, final List<AttackStrategy> standardActions, final List<Actions> attacks){
        return new Weapon(name, damage, standardActions, attacks);
    }

Attack Interface and Implementation:

public interface AttackStrategy{ 
  void attack(Enemy enemy); 
} 

public class Shoot implements AttackStrategy { 
  public void attack(Enemy enemy){ 
    //code to shoot 
  } 
} 
    
public class Strike implements AttackStrategy { 
  public void attack(Enemy enemy){
    //code to strike 
  }
}

'm not asking if I've implemented the Strategy Pattern correctly, but rather can I use the pattern when faced with a subclass that has a method unique to that subclass and I don't want to cast it? or in other words, rather than violate the LSP, can I prohibit the use of inheritance and use the Strategy Pattern to implement the require methods?

Notes:
The pattern solves my problem in 2 ways:

  • I don't have to downcast, I can store my Weapons in a List<Weapon> collection without worrying about checking the type, and then casting
  • Any weapon that isn't Reloadable, won't have the concrete class Reload. This mean no throwing or leaving the method blank

 

Edited by SvetlanaRosemond

Share this post


Link to post
Share on other sites
Advertisement

It sounds like you still have a ReloadableWeapon class.  My question to you is, if you're baking behavior into strategies, why do you still have a ReloadableWeapon class?  Presumably your weapon's AttackStrategy can deal with ammo management.  That way you make downcasting not a problem by not having anything to downcast to.

It's common for weapon code to go a step further and abstract even further than strategies (to the point of data-driving everything), but you're thinking on the right track.

Edited by SeraphLance

Share this post


Link to post
Share on other sites

I think your basic premise of Sword and Rifle belonging in the same class hierarchy is wrong, or your Sword definition is wrong, or your Weapon definition is wrong.

The simple solution is to unify how a sword and a rifle work, by adding a Reload method to the Sword. It's a silly thing in terms of reality, but we're not interested in reality modeling, we're writing a game. This unifies both weapons, and your entire problem disappears like snow in the sun.

The second option is to acknowledge they're different weapons. The game character does something different with a Rifle. The simple solution is then to make them truly different things, each in their own hierarchy. This is not different from not having Money in the same class hierarchy, even though it could be used as a weapon (bar of gold dropped from a 10 story building can severely damage you!).

Your Strategy acknowledges the weapons are different, and then you add another layer of software that hides the difference. You make new instances of the strategy class that basically encodes how to handle each type of weapon, inside the weapon itself.

In other words, your current notion of Weapon is flawed, and to correct it, you add a wrapper layer around it to unify the interface?

 

Is that not equivalent to unifying to a new weapon class that just has a "useIt" method and nothing else? The Reload becomes a hidden implementation detail. Wouldn't it be simpler to just ditch the Strategy, and make a simpler Weapon definition where you directly encode the weapon behavior, where Reload could be a private sub-function of Rifle.

 

Share this post


Link to post
Share on other sites

IMO the strategy pattern is not exactly the way to go, because we do not have a one-time configuration problem here. Instead, items (where weapons count to) in game have several usages from which the player or AI selects one at a time and another at a later time. E.g. striking with a rifle or sticking with a bayonet or emitting lightning bolts from a sword or shooting bullets as well as grenades with the same weapon ... Hence the amount of charges (as generalization of ammo) is not exactly part of the class Item but belongs to the particular action you want to be able to do with the Item.

So let us assume that there is a class ActionObjectA that (when an instance is attached) defines that the item can be used as an object of some actions (in the grammatical sense). The ActionObjectA class has some properties that are meaningful with respect to that set of actions, so that those actions can be selected if and only if that ActionObjectA is attached. Additionally, stuff like adding the set of actions for selection only if the item is hold in hand can be added simply.

Example: Let ActionObjectA be BulletFirearm with properties for the current amount of bullets and the reload amount of bullets. The actions belonging to it may be "shoot bullet" and "reload bullets". When the player controller / AI selects the "shoot bullet" action, the action dispatcher invokes the action class asking whether execution of the action is actually possible just now. The action looks at the properties and returns "true" if at least one bullet is loaded. Hence the action will be invoked to execute.

Notice that there is a collection of dump data (the ActionObjectA, ActionObjectB, ...) and belonging but separated active components (the actions). Notice further that the meaning of the item is defined by which ActionObject* instances are added, perhaps even at runtime (e.g. weapon modifications).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
  • Advertisement
  • Popular Tags

  • Similar Content

    • By MelonCollie
      Hi Everyone,

      My name is Bob Pepek, I'm an audio post production engineer for film / TV. I'm looking to try my hand at Game Audio. Did you know that great sound design is rarely ever noticed but is always felt by an audience? That's where I can help.
      I've worked as the dialogue editor and sound designer for Sprout / NBC's Saturday morning cartoon Astroblast. I sound design for the web-series Channelate (hosted by Explosm / Cyanide and Happiness). Though most notably work as the go-to sound designer for the hundreds of the LEGO Star Wars / Marvel / Ninjago product animations and mini-movies.

      My past sound design clients include NBC, ESPN, LucasArts, LEGO, Sprout Network, Disney, Sci-Fi Network, Walmart,  Sesame Street, The list goes on and on! Below I've included a link to my demo reel as well as other projects I have done sound design for:

      Sound Design Reel
      https://vimeo.com/214093302

      Other Work (Channelate, Explainer Vids, Ads)
      meloncollieproductions.com/work/

      360 Sound Designs (LEGO Star Wars / Avengers: Infinity War)
      https://www.youtube.com/watch?v=-Gdss2fANPQ
      https://www.youtube.com/watch?v=mj7Leyaq780
      https://www.youtube.com/watch?v=LJzPu_tw6eY

      Recent Film Work:
      https://www.youtube.com/watch?v=hbFXobIMAgM
      https://vimeo.com/273203490
      https://vimeo.com/229448486

      If you're looking for a sound designer I'd love to help out! Feel free to reach out at bobpepek@gmail.com. 

      Cheers,
      Bob
    • By Inbar_xz
      I'm using the OPENGL with eclipse+JOGL.
      My goal is to create movement of the camera and the player.
      I create main class, which create some box in 3D and hold 
      an object of PlayerAxis.
      I create PlayerAxis class which hold the axis of the player.
      If we want to move the camera, then in the main class I call to 
      the func "cameraMove"(from PlayerAxis) and it update the player axis.
      That's work good.
      The problem start if I move the camera on 2 axis, 
      for example if I move with the camera right(that's on the y axis)
      and then down(on the x axis) -
      in some point the move front is not to the front anymore..
      In order to move to the front, I do
      player.playerMoving(0, 0, 1);
      And I learn that in order to keep the front move, 
      I need to convert (0, 0, 1) to the player axis, and then add this.
      I think I dont do the convert right.. 
      I will be glad for help!

      Here is part of my PlayerAxis class:
       
      //player coordinate float x[] = new float[3]; float y[] = new float[3]; float z[] = new float[3]; public PlayerAxis(float move_step, float angle_move) { x[0] = 1; y[1] = 1; z[2] = -1; step = move_step; angle = angle_move; setTransMatrix(); } public void cameraMoving(float angle_step, String axis) { float[] new_x = x; float[] new_y = y; float[] new_z = z; float alfa = angle_step * angle; switch(axis) { case "x": new_z = addVectors(multScalar(z, COS(alfa)), multScalar(y, SIN(alfa))); new_y = subVectors(multScalar(y, COS(alfa)), multScalar(z, SIN(alfa))); break; case "y": new_x = addVectors(multScalar(x, COS(alfa)), multScalar(z, SIN(alfa))); new_z = subVectors(multScalar(z, COS(alfa)), multScalar(x, SIN(alfa))); break; case "z": new_x = addVectors(multScalar(x, COS(alfa)), multScalar(y, SIN(alfa))); new_y = subVectors(multScalar(y, COS(alfa)), multScalar(x, SIN(alfa))); } x = new_x; y = new_y; z = new_z; normalization(); } public void playerMoving(float x_move, float y_move, float z_move) { float[] move = new float[3]; move[0] = x_move; move[1] = y_move; move[2] = z_move; setTransMatrix(); float[] trans_move = transVector(move); position[0] = position[0] + step*trans_move[0]; position[1] = position[1] + step*trans_move[1]; position[2] = position[2] + step*trans_move[2]; } public void setTransMatrix() { for (int i = 0; i < 3; i++) { coordiTrans[0][i] = x[i]; coordiTrans[1][i] = y[i]; coordiTrans[2][i] = z[i]; } } public float[] transVector(float[] v) { return multiplyMatrixInVector(coordiTrans, v); }  
      and in the main class i have this:
       
      public void keyPressed(KeyEvent e) { if (e.getKeyCode()== KeyEvent.VK_ESCAPE) { System.exit(0); //player move } else if (e.getKeyCode()== KeyEvent.VK_W) { //front //moveAmount[2] += -0.1f; player.playerMoving(0, 0, 1); } else if (e.getKeyCode()== KeyEvent.VK_S) { //back //moveAmount[2] += 0.1f; player.playerMoving(0, 0, -1); } else if (e.getKeyCode()== KeyEvent.VK_A) { //left //moveAmount[0] += -0.1f; player.playerMoving(-1, 0, 0); } else if (e.getKeyCode()== KeyEvent.VK_D) { //right //moveAmount[0] += 0.1f; player.playerMoving(1, 0, 0); } else if (e.getKeyCode()== KeyEvent.VK_E) { //moveAmount[0] += 0.1f; player.playerMoving(0, 1, 0); } else if (e.getKeyCode()== KeyEvent.VK_Q) { //moveAmount[0] += 0.1f; player.playerMoving(0, -1, 0); //camera move } else if (e.getKeyCode()== KeyEvent.VK_I) { //up player.cameraMoving(1, "x"); } else if (e.getKeyCode()== KeyEvent.VK_K) { //down player.cameraMoving(-1, "x"); } else if (e.getKeyCode()== KeyEvent.VK_L) { //right player.cameraMoving(-1, "y"); } else if (e.getKeyCode()== KeyEvent.VK_J) { //left player.cameraMoving(1, "y"); } else if (e.getKeyCode()== KeyEvent.VK_O) { //right round player.cameraMoving(-1, "z"); } else if (e.getKeyCode()== KeyEvent.VK_U) { //left round player.cameraMoving(1, "z"); } }  
      finallt found it.... i confused with the transformation matrix row and col. thanks anyway!
    • By HomeBrewArcana
      Hey All,
      I'm looking to get into the gaming industry. I've skirted around the idea for a long time, always thinking that I couldn't do it. I've finally decided to take the plunge.
       
      My question is whether it's worth going to school for game design/coding etc. I've been writing content for paper games for a while, and have a good idea of story and some basic design. But I have next to no technical know how. 
       
      My instinct is that such things can be learned with a lot of practice, video tutorials, and more practice. I've also heard that a degree is not really that important, since you get hired based on your portfolio/prototypes. Why not just make the games?
      But won't a degree help with contacts and mentoring--I'm not a great networker.
       
      Of course, it'll plunge me into more debt, but...
      If anyone has advice, let me know. Also any idea of a program to start with: Game Maker, Unity, Godot, Construct, Stencyl--I've heard good things about them all, so much so that I don't know which would be best to start with!
       
      Thanks
    • By Luca Falco
      https://www.youtube.com/watch?v=UMoc52DEoC8     ABOUT THE GAME: Room54 is a first-person Horror/adventure  Videogame for pc,mac and linux users. the game is currently under development by a very small team, we put so much effort in this project and we are keep doing our best for that we are going to launch a kickstarter campaing in order to reach our ideal budget to complete the project, we hope the GameDev community can help us a lot                      STORY:   Daniel is a family father like many other, one day he decide with your wife and his daughter  to spend her winter holidays at their mountain house that they have recently buy in  mountain ,a  wonderful place surrounded by the nature of the woods,  Completely far away from the caotic city life. During their holidays Daniel and his family will understand that they are not welcome there and they will discover an  hided and disturbing part of the valley that they have never seen before                       GAMEPLAY:   You will play as Daniel, a father that will try to save his family, your gameplay will be focused on discovering secrets places around valley,investigating and trying to survive, you will find object that will help you solve enigma and to stay alive. The immersive audio and  environment will make you feel constantly follow by an high anxiety dose  during the game.                         SOCIAL PAGES:     Follow us to get the latest development news and insights     IndieDB:     http://www.indiedb.com/games/room54   Twitter:       https://twitter.com/Room54Thegame   facebook:   https://www.facebook.com/Room54/
    • By Developer Dre Reid
      Hello fellow game devs I am seeking some answers to a somewhat simple question. Now I always thought that when a dev was going to work on a new game to publish he/she should keep some aspects secret infill time to release then he/she can give out needed information pertaining to the game to the public as a marketing tactic. However I had a discussion with other game devs who stated that my way was somewhat not right and the only reason I had such thoughts was due to me being a smaller indie dev who was afraid of having my idea stolen. 
      Therefore I would honestly like to know if my way was right or were the other devs correct. If I were to start working on a new game and give out information about it online via social media would I be risking my idea being stolen and it being made faster and better by another developer or team of developers. Am...Am I paranoid??? 
    • By shadow_archer
      hello!
      so i had this idea of a game i wanted to make that i had in mind for years and i wanted to try to execute it (at least partiality).
      problem is, i don't really know what kind of game style this game can fall under and i don't really know where to start learning sources and design wise :/ .
      i want to create a management style game and all the controls the user has are through a menu of some sort similar to this (this particular example is from a game called '911 operator' by jutsu games):

      to find more information about how i can create such a game i really want to know what's the name of this style of game, mostly GUI controlled game.
      aside from that i'm looking for a bit of advice,
      which engine would be best for such a game? i'm fluent in C++,C# and python so any game engine you can throw at me is great!
      are there any good sources to learn from before jumping into this kind of game, tutorials of some sort perhaps?
       
      thanks so much to anyone who answers, this really means a lot to me!
    • By orion87
      I know that pre-rendered games use images of 3D scenes rendered on other hardware; then these images are used as backgrounds. I was wondering if the power of the console is irrelevant to visualize these images. What I mean exactly is: if the console only visualizes these images, and so it must not compute them as it does with games rendered in real time, is it possible that a pre-rendered game, created with the more sophisticated hardware and techniques today, can be visualized correctly with a console like Playstation 1 without problems (resolution and some other factor aside)? For example, to use pre-rendered images like those of Resident Evil 0 (Nintendo Gamecube) on the Playstation 1. Or does the console has its limits regarding the pre-rendered images which it is able to visualize?
      Another question which connects to the previous one: what is the difference between pre-rendered images of games and the realistic scenarios used by architects etc? Can those realistic scenarios used as pre-rendered backgrounds? I did this reasoning: if with my dated computer (so with my Nvidia Geforce go 7300 Turbocache) of 2006 I can visualize renderings created with the most advanced hardware today, this should be the same regarding the matter of pre-rendered backgrounds created today with the most advanced hardware, put in old consoles like Playstation 1. Is this reasoning correct?
    • By Pixeye
      ACTORS is a small framework explicitly built for Unit3d. It is used to ease the pain of decoupling data from behaviors without tons of boilerplate code. It relies on Unity3d scripting monobehavior concept but without unnecessary overhead.   All game related entities are called Actors - they inherit from monobehavior and take role of container of data and behavior components.  Like that :   public class ActorPlayer : Actor, ITick { [FoldoutGroup("Setup")] public DataMove dataMove; protected override void Setup() { Add(dataMove); Add<BehaviorInput>(); } } [System.Serializable] public class DataMove : IData { public float x; public float y; public void Dispose() { } } public class BehaviorInput : Behavior, ITick { [Bind] private DataMove dataMove; public override void OnTick() { dataMove.x = Input.GetAxis("Horizontal"); dataMove.y = Input.GetAxis("Vertical"); } } The framework includes:
      Time management Custom Update Management.   While Monobehavior update method can be used only with inherited mono components, you can use framework Update method in ANY script.
      public class MyCustomClass : ITick{ public MyCustomClass(){    ProcessingUpdate.Default.Add(this); } public void Tick(){      } }  
      Object pooling both for game objects and plain c# objects Signal-event system Toolbox-singleton ( a simple servie locator ) Simple ECS for actors  Unity additive scenes solution Blueprints - scriptable objects to define common actors data Extended tags system Timers for delayed action Timer.Add(0.75f, () => actor.tags.Remove(Tag.StateImmortal)); FoldGroup attribute to make your inspector look more organized:


       
      Bind attribute for lazy initialization of components inside of behaviors
        [Bind] private DataMove dataMove;   Currently I'm working on documentation and example projects. I use framework in my working projects and always keep it updated. 
  • Advertisement
  • Popular Now

  • Forum Statistics

    • Total Topics
      631378
    • Total Posts
      2999665
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!