Reputation: 49
Ok, due to poor configuration on server side response I am having trouble finding an efficient way to go about writing my code.
Since the example i'm trying to convey is rather complex, I will try and use a real life example to help.
So lets say I am in charge of a sports rewards program and I am trying to attempt to create a "Top Athletes Page". The page will display the top male and female athletes from a category of three sports; baseball, basketball, and football. A twist to this is that there could be one male winner and no female winner, vice versa, or no winners at all. On top of that, a female can only be a baseball player or basketball player, whereas a male could be either of the three OR both a basketball player and football player. There is no combination of baseball with anything else. Lastly, if both male and female player exist, female must be displayed first. All three categories have different attributes such as football would have a "tds = 43" attribute compared to baseball "Homeruns = 32".
So the confusion comes into play with the server response:
<player>
<baseballList>
<baseball
name="Adam"
sex="male"
HomeRuns="32"
reward="True"/>
</baseballList>
<basketballList>
<basketball
name="John"
sex="male"
Points="322"
reward="False"/>
<basketball
name="Sandra"
sex="female"
Points="332"
reward="True"/>
</basketballList>
<footballList>
<football
name= doug
Touchdowns= 33
sex=male
reward="false"/>
</footballList>
</player>
(if the player name matches for both football and basketball and is male is when you would combine the 2) As you see the response is sending back players that aren't of interest (dont ask why) that I have to filter out, as well as it doesn't combine data when a player has multiple sports. So for my approach I have a xml handler factory that sends the xml to the specified "Players" handler. Which would look something like:
public class PlayerHandler implements XmlHandler {
private static PlayerHandler handler = new PlayerHandler();
private PlayerHandler() {
}
public static PlayerHandler getInstance() {
return handler;
}
public void load(String localName, String qName, Attributes attributes) {
if (localName != null && attributes != null) {
if (localName.equalsIgnoreCase("football")||localName.equalsIgnoreCase("baseball")||localName.equalsIgnoreCase("basketball")) {
Player player = new Player();
if (localName.equalsIgnoreCase("football"))
player.category = "football"
player.TouchDowns=attributes.getValue("TouchDowns");
else if (localName.equalsIgnoreCase("baseball"))
player.HomeRuns=arrtibutes.getValue("HomeRun");
player.category = "baseball"
else{
player.category = "basketball";
player.Points=attributes.getValue("Points");}
player.sex=attributes.getValue("sex");
player.name=attributes.getValue("name");
}
playerSorter.addPlayer(player);}}
I created one class file for the objects:
public class Player implements Serializable{
public String category;
public String rewards;
public String TouchDowns;
public String Points;
public String HomeRuns;
public String sex;
public String Name;
}
I am doing all of my sorting with a class called "playerSorter" with a addPlayer() method that only populates the list if the specified criteria is met, then i have a getPlayers() method which calls my checkForAthleteWithInTwoSports() method (goes through and sees if theres a player thats in both basketball and football) than returns a sorted list with the woman showing first (if applicable). The getPlayers() method is called from my main page, then sets it to an adapter class. A better xml response would make a task like this MUCH easier, however that's not the case and I want to find a more efficient way to do this. If anyone could help me find a good design pattern to tackle this with or any advice I would really appreciate it.(Also, the categories have more attributes than just "HomeRuns, points, or touchdowns" just trying to simplify.)
Upvotes: 0
Views: 338
Reputation: 1693
I don't know if there is a specific design pattern here to solve your problem; from my point of view your model is missing some abstractions, since you are mostly using strings to represent your domain model. This kind of goes against OOP, where the idea is to represent things with objects, so that you can delegate behavior to them. As an example consider this piece of code:
if (localName.equalsIgnoreCase("football"))
player.category = "football"
player.TouchDowns=attributes.getValue("TouchDowns");
else if (localName.equalsIgnoreCase("baseball"))
player.HomeRuns=arrtibutes.getValue("HomeRun");
player.category = "baseball"
else{
player.category = "basketball";
player.Points=attributes.getValue("Points");}
This can be easily improved by creating three classes to represent each sport performance (FootballPerformance
, BaseballPerformance
and BasketballPerformance
), where each class holds the attributes that apply to them. Once you have that, you can delegate the reading of the XML node to the class itself (please bear with me here, I'm not a Java programmer, so I'll use pseudocode):
public class BasketballPerformance extends SportPerformance {
private Integer points;
//Constructor
public BasketballPerformance(Attributes attributes)
{
this.points = attributes.getValue("Points");
}
public getPoints()
{
return this.points;
}
}
The classes FootballPerformance
and BaseballPerformance
are quite similar, taking a set of attributes and populating themselves based on them. By applying the same idea to the Player
class also you can decentralize the objects creation into something like:
public Sport createSportPerformanceInstance(String name, Attributes attributes)
{
if (name.equalsIgnoreCase("football"))
{return new BasketballPerformance(attributes);}
else
if (name.equalsIgnoreCase("baseball"))
{return new BaseballPerformance(attributes);}
...
}
public void load(String localName, String qName, Attributes attributes)
{
SportPerformance sportPerformance = this.createSportPerformanceInstance(localName, attributes);
Player player = new Player(Attributes attributes);
player.sportPerformance = sportPerformance;
}
Note that as a nice side-effect, if you later add a new sport you only need to implement the new class and add a new branch in the createSportPerformanceInstance
method instead of diving into one single large method.
The code can be later improved by having a Player
hold a collection of performances instead of just one and having the PlayerHandler
check for the existence of a player before creating a new one. The new method would look something like this:
public void load(String localName, String qName, Attributes attributes)
{
SportPerformance sportPerformance = this.createSportPerformanceInstance(localName, attributes);
String playerName=attributes.getValue("name");
Player player;
if (!this.playerExists(playerName))
{
player = new Player(attributes);
} else
{
player = this.getPlayerByName(playerName);
}
player.addPerformance(sportPerformance);
}
The nice thing is that now you can delegate the sort order to the players themselves by implementing the Comparable
interface and the model also fits better the reality that you are trying to model, since you have one player that has different performances on different sports.
Having said that, you may find some inspiration in the Creational design patterns, specially in the Builder, Factory and Abstract Factory.
HTH
Upvotes: 1