HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Combining two classes to hold general and specific properties of an item

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
itemcombiningpropertiesgeneraltwoholdclassesspecificand

Problem

I have an ItemData class in my program that stores saved data about a game inventory item that can change, such as its durability, quality, number of bullets in the clip and similar. ItemClass, on the other hand, lives in a DLL, and holds data that is always true for specific item, such as its name, max durability, size of the clip and similar, regardless of its state.

I believe the two classes should be combined using some standard design pattern, but I'm not sure how.

ItemClass is in a DLL that loads data from a specific file type and then presents that data in this form.

public class ItemClass
{
    public byte itemVersion;
    public int type;
    public int timesUsed;
    public int quality;
    public int meta;
    public ItemClass[] parts = new ItemClass[0];
    public List moreParts= new List();
    public bool activated;
    public byte index;

    //Some methods specific to this class
}


I actually wrote the library, so I could change it, but I would rather not break encapsulation or make the library dependent on the program.

This class is in my program:

```
public class ItemData
{
public static List itemList = new List();

public const int MAX_QUALITY = 5;
public const int DEFAULT_STACKNUMBER = 100;

public int id;
public string name;
public int stackNumber = 0;

public bool isBlock = false;
public bool hasQuality = false;
public int degradationMin = 0;
public int degradationMax = 0;
public int magazineSize = 0;
public string partType = "";
public string[] morePartsNames;
public string[] partNames;
public string[] magazineItems;
public byte[] iconPixels;

public bool isDeveloper = false;

public static ItemData GetItemDataById(int id)
{
foreach (ItemData itemData in itemList)
{
if (itemData.id == id)
{
return itemData;
}
}

return null;
}

//Some more methods specific to

Solution

You make it more complicated then necessary. The duplication of all properties in the ItemBinder is a manintenace hell.


I have this whole situation in two places in my program, and as it expands, there may be more.

If you add more properties then you need to update two data structures.

It would be enough if you just created a FullItem like:

public class FullItem
{
    public ItemClass itemClass;
    public ItemData itemData;
}


and build it with a simple join:

var classess = new ItemClass[] 
{
    new ItemClass{ type = 1 },
    new ItemClass{ type = 2 },
};

var data = new ItemData[]
{
    new ItemData { id = 1 },
    new ItemData { id = 2 },
};

var fullItems = classess.Join(data, c => c.type, d => d.id, (c, d) => new FullItem 
{ 
    itemClass = c, 
    itemData = d 
}).ToList();


now you can extend either class and don't worry about copying any properties.

Code

We really don't use public fields. All of them should be properties whose names are in PascalCase:

public class ItemClass
{
    public byte ItemVersion { get; set; }
}


public static List itemList = new List();


Storing the results in a static field (it actaully should be a property if any) in the same class is not a good idea.

The method loding the data should return a collection and you should store the result in your application not in the library.

type & id

This is very confusing as the names do not implicate any relation. If the ItemClass has a Type property then then foreign-key in the ItemData should be called ItemClassType. The Join would be much more natural then and self explaining:

var fullItems = classess.Join(
    data, 
    itemClass => itemClass.Type, 
    itemData => itemData.ItemClassType, 
    (itemClass, itemData) => new FullItem 
    { 
        ItemClass = itemClass, 
        ItemData = itemData 
    }).ToList();


Alternative solution (not recommended - can cause maintenace problems) but this way you at least avoid copying the values and use the original objects for storing them:

public class FullItem
{
    public FullItem(ItemClass itemClass, ItemData itemData)
    {
        ItemClass = itemClass;
        ItemData = itemData;
    }

    private ItemClass ItemClass { get; }

    private ItemData ItemData { get; }

    public string Value 
    { 
        get { return ItemClass.Value; } 
        set { ItemClass.Value = value; }
    }
}

Code Snippets

public class FullItem
{
    public ItemClass itemClass;
    public ItemData itemData;
}
var classess = new ItemClass[] 
{
    new ItemClass{ type = 1 },
    new ItemClass{ type = 2 },
};

var data = new ItemData[]
{
    new ItemData { id = 1 },
    new ItemData { id = 2 },
};

var fullItems = classess.Join(data, c => c.type, d => d.id, (c, d) => new FullItem 
{ 
    itemClass = c, 
    itemData = d 
}).ToList();
public class ItemClass
{
    public byte ItemVersion { get; set; }
}
public static List<ItemData> itemList = new List<ItemData>();
var fullItems = classess.Join(
    data, 
    itemClass => itemClass.Type, 
    itemData => itemData.ItemClassType, 
    (itemClass, itemData) => new FullItem 
    { 
        ItemClass = itemClass, 
        ItemData = itemData 
    }).ToList();

Context

StackExchange Code Review Q#142755, answer score: 2

Revisions (0)

No revisions yet.