I think that I have big problems with object-oriented analysis of a problem and with writing really good, object-oriented code based on the analysis. When I was trying to write an RPG, it struck me that as a beginner, it is very difficult to plan everything in detail and translate it into good code.
I will explain below how I have implemented a specific problem in code. Some things seem awkward. This is because the code will be extended later and should serve here only as an illustrative example.
The Idea
In role-playing games, a player has abilities that he claims to be in the game world. These skills can be improved. I would like to analyze this seemingly simple aspect analytically.
The concrete Problem
There is a being, that has skills. He can improve the level of his skills with paying money. He can’t do it alone. He needs a trainer for that.
We can see, that we have three specific actors. The being, the skill and the trainer.
The being has (a) skill(s) and wants to improve them with his money.
That leads us to the following structure:
class Player has: gold, skill(s) can: improve his skills class Skill has: level can: exert hisself class Trainer has: gold can: improve skills of a being that has skills
Implementation
Very often I notice things during the implementation that I did not consider in the analysis and design of the pseudocode. As a result, the implementation is very different from the actual design, and in the worst case becomes illegible.
Again, it happened to me that I noticed facts that I did not consider. For example, that the trainer and the player need additional methods that can be summed up in a superclass.
The player and the coach exchange money with each other. Appropriate methods are needed.
Human.java
public class Human { protected int gold; public Human(int gold) { this.gold = gold; } public void receiveGold(int value) { if(gold > 0) { gold += value; } } public void payGold(Human human, int value) { if(gold >= value) { human.receiveGold(value); } } }
The class Player
is relatively self-explanatory. There are no noteworthy deviations from the plan.
Player.java
public class Player extends Human { private Skill skill; public Player(int gold, Skill skill) { super(gold); this.skill = skill; } public void improveSkill(Trainer trainer) { int price = trainer.train(skill, gold); payGold(trainer, price); } }
This could be a class that represents a skill. It can be improved. Taking money for that is the job of the trainer.
Skill.java
// objects from this classes represent an ability, a skill public class Skill { private String name; private int level; public Skill(String name, int level) { this.name = name; this.level = level; } public int getLevel() { return level; } // what the skill actually does has to be defined in a child class public void exert() { // do something } public void improve(int value) { if(value > 0) { level += value; } } }
The Trainer
can improve a skill of a player or another Being.
Trainer.java
// trainers can improve the skill of a human public class Trainer extends Human { public Trainer(int gold) { super(gold); } public int train(Skill skill, int gold) { int price = skill.getLevel() * 5; if(price <= gold) { skill.improve(1); } return price; } }
All this can only happen if a matrix is created for it, in which the different entities can interact with each other. I called this class Environment
.
Environment.java
public class Environment { private Player player; private Trainer trainer; public Environment() { player = new Player(20, new Skill("Pottery", 1)); trainer = new Trainer(5); } // now it has to happen! public void takePlace() { player.improveSkill(trainer); // the trainer is nice and wants to pay the money back trainer.payGold(player, 10); } public static void main(String [] args) { Environment e = new Environment(); e.takePlace(); } }
What do you think of my implementation of the problem? Did I follow the rules of object orientation, or did I start any style breaks? Are there things that are unattractive or cumbersome and can be better implemented in other ways?
Now if I want to refine the program with textual output, where should the appropriate commands stand? Right there, where the things do happen, or should these commands be outsourced to an external class?