Related
I want to create configuration for my application using static classes.
Firstly please forgive my ignorance, I'm not a full time c# dev. I come from a Ruby/Javascript world where dynamic access to constants & variables is trivial.
Whether or not this is the right approach here I'm not 100% at the moment. Would be greatful of other suggested approaches.
I have the following static class setup for my config:
public static class Config
{
public static class MaterialQuality
{
public static class Low
{
public const float Value = 0.1f;
public const int Cost = 10;
}
public static class Medium
{
public const float Value = 0.2f;
public const int Cost = 20;
}
public static class High
{
public const float Value = 0.2f;
public const int Cost = 40;
}
}
}
I then have a class Material, which is passed an enum value relating to the aboves types Low,Medium,High.
The reason for the enum in unity this gives a quick way for devs to provide level designers with an option list for a an object.
So by choosing an enum value the level designer can set the properties stored in the config without actually having to enter the values directly onto the object. The values are set against the object when it is initialised.
In the constructor I want to set member variables for Cost & Value from the static config values for the MaterialQuality enum value passed.
public enum MaterialQuality
{
Low,Medium,High
}
public class Material
{
private int Cost;
private float Value;
Material(MaterialQuality quality) {
Cost = Config.MaterialQuality.<quality>.Cost;
Value = Config.MaterialQuality.<quality>.Value;
//in Javascript I'd use associative array access to the object
Cost = Config.MaterialQuality[quality].Cost;
//in Ruby we have const_get() on classes.
Cost = Config.MaterialQuality.const_get(quality).Cost
}
}
The main reason for this approach is to provide single place for configuration & provide a fairly simple way for a non technical person to make changes to parts of the application without having to delve into the main classes. Also it allows me to take advantage of the constants being available in intellisense.
I'm a fan of using dictionaries for this type of configuration.
void Main()
{
var config = Config.Qualities[MaterialQualities.Low];
var cost = config.Cost;
var value = config.Value;
}
public static class Config
{
public static Dictionary<MaterialQualities, MaterialQuality> Qualities =
new Dictionary<MaterialQualities, MaterialQuality>
{
{ MaterialQualities.Low, new MaterialQuality { Value = 0.1F, Cost = 10 }},
{ MaterialQualities.Medium, new MaterialQuality { Value = 0.2F, Cost = 20 }},
{ MaterialQualities.High, new MaterialQuality { Value = 0.2F, Cost = 40 }},
};
}
public class MaterialQuality
{
public float Value { get; set; }
public int Cost { get; set; }
}
public enum MaterialQualities
{
Low, Medium, High
}
Probably better approach would be:
public static class Config
{
public class Material
{
public Material(float value, int cost){
Value = value;
Cost = cost;
}
public float Value {get; private set;}
public int Cost {get; private set;}
public Material GetFor(MaterialQuality quality){
switch(quality){
case MaterialQuality.Low: return new Material(0.1f, 10);
case MaterialQuality.Medium: return new Material(0.2f, 20);
case MaterialQuality.High: return new Material(0.2f, 40);
}
throw new Exception("Unknown material quality " + quality);
}
}
}
and later you can use that:
//....
Material materialData = Material.GetFor(quality);
Cost = materialData.Cost;
Value = materialData.Value;
//...
I would use a struct and static properties in MaterialQuantity instead of an enum. Something like the following:
public struct MaterialQualityInfo
{
public MaterialQualityInfo( float value, int cost )
{
Value = value;
Cost = cost;
}
public float Value { get; private set; }
public int Cost { get; private set; }
}
public static class Config
{
public static class MaterialQuality
{
public static MaterialQualityInfo Low
{
get { return new MaterialQualityInfo( 0.1f, 10 ); }
}
public static MaterialQualityInfo Medium
{
get { return new MaterialQualityInfo( 0.2f, 20 ); }
}
public static MaterialQualityInfo High
{
get { return new MaterialQualityInfo( 0.2f, 40 ); }
}
}
}
public class Material
{
private int Cost;
private float Value;
Material( MaterialQualityInfo quality )
{
Cost = quality.Cost;
Value = quality.Value;
}
}
IMHO, this isn't a good usage of static classes. You should use regular object-oriented programming to solve the issue.
I see that all material qualities have 2 properties in common: Value and Cost. For me, this means that you should design a class called MaterialQuality:
public class MaterialQuality
{
public float Value { get; set; }
public int Cost { get; set; }
}
If material qualities are part of an application configuration, I see that you should design a Configuration class as follows:
public class Configuration
{
public List<MaterialQuality> MaterialQualities { get; } = new List<MaterialQuality>();
}
...and if you want to initialize a configuration per application life-cycle, you can improve Configuration class using static field initializers:
public class Configuration
{
private readonly static Configuration _current = new Configuration();
public static Configuration Current => _current;
public List<MaterialQuality> MaterialQualities { get; } = new List<MaterialQuality>();
}
Now adding new material qualities to current configuration is as easy as the following code:
Configuration.Current.MaterialQualities.Add(new MaterialQualities { Value = 0.1f, Cost = 10 });
If you want to provide a fluent API to add material qualities is also easy: we're going to turn public MaterialQualities properties into an ImmutableList<T> (so you force developers to add materials using the method to do so) and add an AddMaterial method:
public class Configuration
{
private readonly static Configuration _current = new Configuration();
private readonly List<MaterialQuality> _materialQualities = new List<MaterialQuality>();
public static Configuration Current => _current;
public IImmutableList<MaterialQuality> MaterialQualities => _materialQualities.ToImmutableList();
public Configuration AddMaterial(float value, int cost)
{
_materialQualities.Add(new MaterialQuality { Value = value, Cost = cost });
return this;
}
}
...and now adding many materials would look even nicer!
Configuration.Current.AddMaterial(0.1f, 10)
.AddMaterial(0.2f, 20)
.AddMaterial(0.2f, 40);
How about:
public enum MaterialQuality
{
Low, Medium, High
}
public class Material
{
private int Cost;
private float Value;
private readonly Dictionary<MaterialQuality, Tuple<int, float>> storageMap = new Dictionary<MaterialQuality, Tuple<int, float>>
{
{ MaterialQuality.Low, Tuple.Create(10, 0.1f)},
{ MaterialQuality.Low, Tuple.Create(20, 0.2f)},
{ MaterialQuality.Low, Tuple.Create(40, 0.2f)},
};
public Material(MaterialQuality quality)
{
Cost = storageMap[quality].Item1;
Value = storageMap[quality].Item2;
}
}
If you are not using your enum widely, you could do something like:
public class Material
{
public float Value { get; private set; }
public int Cost { get; private set; }
public Material(float value, int cost)
{
Value = value;
Cost = cost;
}
public static Material Low { get { return new Material(0.1f, 10); } }
public static Material Medium { get { return new Material(0.2f, 20); } }
public static Material High { get { return new Material(0.2f, 40); } }
}
And then:
var myLowMaterial = Material.Low;
var myMediumMaterial = Material.Medium;
var myHighMaterial = Material.High;
Unless you are using your enum for something, in which case you could add:
public static Material Get(MaterialQuality quality)
{
switch(quality)
{
case MaterialQuality.Low:
return Low;
case MaterialQuality.Medium:
return Medium;
case MaterialQuality.High:
return High;
}
throw new Exception("We should never go here");
}
So I'm quite new to programming in general. I'm currently working on a terrain generation program, everything is going great except for this:
public static class Desert
{
public const int iChance = 15;
public static int chance = iChance;
public static int chancepoint = 0;
public const int octaves = 4;
public const int lengthMin = 60;
public const int lengthMax = 90;
public const float scaleMin = 250;
public const float scaleMax = 350;
public const float persistenceMin = 0.5f;
public const float persistenceMax = 0.9f;
public const pType ptype = pType.Lowland;
public const bTag[] tags = { bTag.desert };
}
public static class Meadow
{
public const int iChance = 45;
public static int chance = iChance;
public static int chancepoint = 0;
public const int octaves = 4;
public const int lengthMin = 45;
public const int lengthMax = 70;
public const float scaleMin = 200;
public const float scaleMax = 470;
public const float persistenceMin = 0.35f;
public const float persistenceMax = 0.70f;
public const pType ptype = pType.noAbs;
public const bTag[] tags = { bTag.lush };
}
These are the properties for each different type of 'Biome'.
I currently have about 7 of these and they're all exactly the same except for the values of each field.
Is there a way that I can shorten the code? I looked into inheritance but I ended up with errors and I got a little confused. ><
It would be brilliant if all I had to write was:
public static class Desert
{
iChance = 15;
chance = iChance;
chancepoint = 0;
octaves = 4;
lengthMin = 60;
lengthMax = 90;
scaleMin = 250;
scaleMax = 350;
persistenceMin = 0.5f;
persistenceMax = 0.9f;
ptype = pType.Lowland;
strongTags = { bTag.desert };
}
Thanks in advance.
Oh, and sorry about the nubness of the question, you would probably scream at how terrible my code was if you saw the rest of the program. XD
EDIT: It's probably wise to tell you that I NEVER change the stuff within the class again with the exception of the value of 'chance'.
Instead of using a static class, you can use a non-static class.
public class Biome {
// Instance fields with default values
public int iChance = 15;
public int chance = iChance;
public int chancepoint = 0;
public int octaves = 4;
public int lengthMin = 60;
public int lengthMax = 90;
public float scaleMin = 250;
public float scaleMax = 350;
public float persistenceMin = 0.5f;
public float persistenceMax = 0.9f;
public pType ptype = pType.Lowland;
public bTag[] tags = { bTag.desert };
}
Here use the constructor for initializing:
public Biome(int iChance, int chance, int chancepoint, int octaves, public int lengthMin, int lengthMax, float scaleMin, float scaleMax, float persistenceMin, float persistenceMax,pType ptype, bTag[] tags) {
// init fields here
}
Then call the constructor:
Biome bimoe = new Biome(15, iChance, 0, 4, 60, 90, 250, 350, 0.5f, 0.9f, pType.Lowland, { bTag.desert });
With this it's difficult to see which parameter goes to which field, but it's much shorter.
If the fields must be read-only, you can make properties with only a public get and no set accessor. Example:
public Chance { get { return chance; } }
In this case make the fields private:
private int chance = iChance;
(Personally, for such a scenario, i would put all the data in a file)
The following would be shorter:
public const int iChance = 15, octaves = 4, lengthMin = 60, lengthMax = 90;
public const float scaleMin = 250, scaleMax = 350, persistenceMin = 0.5f,
persistenceMax = 0.9f;
public static int chance = iChance, chancepoint = 0;
However... these really don't look like things that should be static fields, or quite possibly not even const. They look like things that should be instance properties. Maybe something like:
public class Terrain {
public int Chance {get;private set;}
public int LengthMin {get;private set;}
// ...
private Terrain(int chance, int lengthMin, ...) {
Chance = chance;
LengthMin = lengthMin;
// ...
}
private static readonly Terrain
desert = new Terrain(45, 45, ...),
meadow = new Terrain(15, 60, ...),
...;
public static Terrain Desert { get { return desert;}}
public static Terrain Meadow { get { return meadow;}}
}
I don't know much about terrain generation programs, but you should store your data in a database.
Then create classes to map that data to your application.
I recommend you to lookup "Data structures" and see which one fits your application the best.
It's better to use only one class without inheritance, or even structure. Desert, Meadow and so on are not classes logically, it's have to be objects (maybe constants).
What you could do is use a single class called Terrain and Initialise this multiple times using a static constructor:
public class Terrain
{
public int IChance { get; private set; }
public int Chancepoint { get; private set; }
public int Octaves { get; private set; }
public int LengthMin { get; private set; }
public int LengthMax { get; private set; }
public float ScaleMin { get; private set; }
public float ScaleMax { get; private set; }
public float PersistenceMin { get; private set; }
public float PersistenceMax { get; private set; }
public pType Ptype { get; private set; }
public bTag[] Tags { get; private set; }
public static Terrain Desert()
{
return new Terrain
{
IChance = 15,
Chancepoint = 0,
Octaves = 4,
LengthMin = 60,
LengthMax = 90,
ScaleMin = 250,
ScaleMax = 350,
PersistenceMin = 0.5f,
PersistenceMax = 0.9f,
Ptype = pType.Lowland,
Tags = new bTag[] {bTag.Desert}
};
}
}
joe's answer is good, but the constructor call has far too many unnamed parameters - what does the 350 mean?
This is an ideal candidate for data driven design.
Rather than define all the Biome types in the code, put all the data for the Biome types into a file and read the file at run time. The C# language has a lot of stuff to help you do this, the key word to search for is Serialisation (and here's a link to MSDN about it).
The big advantage is that you can change the data values without needing to recompile the code.
The disadvantage is that is takes a lot more code to define the first instance, but after that, you can easily create as many instances as you want.
You could do something like declaring an abstract class like this and then inherting from it:
public abstract class Terrain
{
public int iChance;
public int chance;
public int chancepoint;
public int octaves;
public int lengthMin;
public int lengthMax;
public float scaleMin;
public float scaleMax;
public float persistenceMin;
public float persistenceMax;
public pType ptype;
public Tag[] strongTags;
}
public class Desert : Terrain
{
}
public enum pType
{
Desert = 1,
LowLand = 2
}
public enum Tag
{
desert = 1,
lush = 2
}
You can then instantiate desert like :
var desert = new Desert()
{
iChance = 15
,chance = 15
,chancepoint = 0
,octaves = 4
,lengthMin = 60
,lengthMax = 90
,scaleMin = 250
,scaleMax = 350
,persistenceMin = 0.5f
,persistenceMax = 0.9f
,ptype = pType.Desert
,strongTags = new Tag[]{Tag.desert}
};
Not sure what your exact requirements are but wouldn't this be a better approach:
public abstract class BiomeBase
{
public int Chance { get; set; }
public int Chancepoint { get; set; }
public int Octaves { get; set; }
// you get the idea ...
}
Then you have Desert and Meadow inheriting:
public class Desert : BiomeBase
{
// everything is inherited ...
// you can also add your own properties meant for Desert only (if needed)
}
public class Meadow : BiomeBase
{
// everything is inherited ...
}
Now Desert has everything Biome has and you can use it like this:
var desert = new Desert
{
Chance = 5,
Octaves = 1,
/// etc
};
Firstly you cant do inheritance on static classes. So you would have to start using instances.
Secondly you would use inheritance if you wanted to extend the object. So for instance if you wanted to add a new property "bool HasScorpions" onto Desert but not on Meadow.
Since your using the same properties but want to use different values I personally use an Interface. This way you can make the properties readonly ect while still easily setting the values.
public interface Terrain
{
int iChance = {get { return 15; private set; } ..and repeat.
int chance = iChance;
int chancepoint = 0;
int octaves = 4;
int lengthMin = 60;
int lengthMax = 90;
float scaleMin = 250;
float scaleMax = 350;
float persistenceMin = 0.5f;
float persistenceMax = 0.9f;
pType ptype = pType.Lowland;
bTag[] tags = { bTag.desert };
}
I have a class created:
public class character
{
public string Name, Owner;
public int Str, Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges;
}
As you can see, it's a very simple class at the moment. My question is, is there a way to create another class inside this so when I call my function I can have a math equation returned?
Example:
character c = new character();
c.Name = "Goofy";
c.Owner = "Me";
c.Str = 15;
MessageBox.Show(c.Str.Mod);
The output to the window would be "7"
(Mod is: Math.Floor(Str / 2);)
I have been trying to search both SO and Google for some time and have yet to figure this out. I may be searching for the wrong phrases or this might not even be possible.
Thanks
only way that I can quickly think is Extension Methods
class Program
{
static void Main(string[] args)
{
character c = new character();
c.Name = "Goofy";
c.Owner = "Me";
c.Str = 15;
Console.WriteLine(c.Str.Mod());
Console.Read();
}
}
public class character
{
public string Name, Owner;
public int Str, Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges;
}
public static class Ext
{
public static int Mod(this int value)
{
return (int)Math.Floor(value / 2.0);
}
}
public class Character // C should be uppercase here.
{
public string Name, Owner;
public int Str, Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges;
public double ModMe()
{
return Math.Floor(this.Str / 2); // Math.Floor returns double
}
}
character c = new character();
c.Name = "Goofy";
c.Owner = "Me";
c.Str = 15;
MessageBox.Show(c.ModMe());
or:
public class character
{
public string Name, Owner;
public int Str, Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges;
public int StrMod{
get{
return (int)Math.Floor(Str / 2);
}
}
}
used with:
character c = new character();
c.Name = "Goofy";
c.Owner = "Me";
c.Str = 15;
MessageBox.Show(c.StrMod);
Yes, you can create a method called Mod that will do your math for you. It'd look something like this:
public class character
{
public string Name, Owner;
public int Str, Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges;
public double Mod(int stat)
{
return Math.Floor(stat/2);
}
}
Create an interface. Use properties. Use descriptive variable names:
public interface ICharacter
{
public string Name { get; }
public int Strength { get; }
}
Then implement it:
public class Character : ICharacter
{
public string Name { get; private set; }
public int Strength { get; private set; }
public Character(string name, int strength)
{
this.Name = name;
this.Strength = strength;
}
}
Now for your question, you should let one class do one thing. So now you can create and initialize a calculator for a character's damage modifier (or whatever "Mod" means):
public class DamageModifierCalculator
{
public int Calculate(ICharacter character)
{
return (int)Math.Floor(character.Strength / 2);
}
}
Now initialize and call it:
var character = new Character("Goofy", 15);
var calculator = new DamageModifierCalculator();
int mod = calculator.Calculate(character);
It's extensible, it's testable and its concerns are separated. You will want to create an interface for the calculator too, as you'll need more of them, preferably one for each kind of calculation.
Or you can just stick it in your Character class, but then it's got nothing to do with OO anymore.
Rather than using Int fields for your stats (at least for your example), make a Stat class, like so:
public class character
{
public string Name, Owner;
public int AC, Speed, maxHP, currHP, AP, SV, Surges;
public Stat Str { get; set; }
public Stat Con { get; set; }
public Stat Dex { get; set; }
public Stat Int { get; set; }
public Stat Wis { get; set; }
public Stat Cha { get; set; }
public class Stat
{
public Stat(int stat)
{
Value = stat;
}
public int Value { get; set; }
public int Mod { get { /*Calcuate Mod from Value.*/; } }
}
}
And call it like this:
character c = new character();
c.Name = "Goofy";
c.Owner = "Me";
c.Str = new Stat(7);
MessageBox.Show(c.Str.Value); //The Value
MessageBox.Show(c.Str.Mod); //The Mod of Strength
For this operation, you can just do :
int x = (int)15 / 2;
Also, you can create nested class, that is to say, a class inside a class.
For example, you would have inside your class something like :
public class MathOperator
{
public int Mod(int x)
{
return (int)x/2;
}
}
And then, just create an instance of this nested class in your class, and use it on c.Str
If Mod is a operation that could apply to any integer, you could define it as an extension method.
static class ExtendInt
{
static public int Mod(this int stat)
{
return stat / 2;
}
}
class UseExtendedInt
{
void UseIt()
{
int a = 1;
int b = a.Mod();
}
}
If you put ExtendInt inside a unique namespace, you can use that namespace only in the files where you want this to work, but otherwise this will be an available function for all integers in that namespace.
If this needs different operations depending on the variable name, you'll have to somehow incorporate reflection or define an enum that identifies the calculation type to pass into Mod.
In most cases, if the calculation types are different, you're better off defining properties like strMod, conMod, etc...
To use that exact syntax, you would need Str to be a different type. One that can be converted from an int and have a property named Mod:
public class character {
// A type that is convertible from int and has a Mod property
public class Modder {
//private variable to hold the integer value
private int _value;
// private constructor that is used by the converter
private Modder(int value){ _value = value; }
// implicit converter to handle the conversion from int
public static implicit operator Modder(int value) {
return new Modder(value);
}
// Property Mod that does the calculation
public int Mod {
get { return _value / 2; }
}
}
public string Name, Owner;
public int Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges;
public Modder Str;
}
I put that class insde the character class, but it doesn't have to be.
public class character
{
public string Name, Owner;
public int Str, Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges;
public int MathFunction(int input)
{
return (int)(input/2);
}
}
now you can use
MessageBox.Show(c.MathFunction(c.Str));
Help me with building object model, please.
I need abstract class Unit representing each military unit in a game. There is Soldier, Tank, Jet and Bunker (children of Unit). Each of them has int properties Count and Defense, constructor with single int count parameter and one method GetTotalDefense.
My idea is following.
private abstract class Unit
{
private int Count { get; set; }
private const int Defense = 0;
protected Unit(int count)
{
Count = count;
}
public int GetTotalDefense()
{
return Count * Defense;
}
}
private class Tank : Unit
{
private const int Defense = 5;
}
Each unit has different Count and different Defense. Body of constructor and body of GetTotalDefense is always the same. What I need is in child class override Defense, because each unit has different. This property should be const, all instances of Tank (Soldier, ...) has same defense. Is there a possibility to inherit const property or each child needs its own const Defense property?
And here is an example I'd like to achieve.
Oh, there is also class Troop
public class Troop
{
private Soldier Soldiers { get; set; }
private Tank Tanks { get; set; }
private Jet Jets { get; set; }
private Fort Forts { get; set; }
public Troop(int soldiers, int tanks, int jets, int forts)
{
Soldiers = new Soldier(soldiers);
Tanks = new Tank(tanks);
Jets = new Jet(jets);
Forts = new Fort(forts);
}
public int GetTotalDefense()
{
return Soldiers.GetTotalDefense() + Tanks.GetTotalDefense() + Jets.GetTotalDefense() + Forts.GetTotalDefense();
}
}
Also, feel free to suggest better solution, thanks.
PS: I'm really strict about access modifiers, so be precise in your examples, thank you.
You can't really use a const but you can make a readonly property also are you sure you want the classes to be private and not internal or public?
public abstract class Unit {
protected Unit(int count) {
Count=count;
}
protected int Count { get; private set; }
protected abstract int Defense {get;}
public int TotalDefense {
get { return Count*Defense; }
}
}
public class Tank : Unit {
public Tank(int count) : base(count) {}
protected override int Defense {
get { return 5; }
}
}
public class Troop {
private Unit[] Troops;
public Troop(int soldiers, int tanks, int jets, int forts) {
Troops = new Unit[] {
new Soldier(soldiers),
new Tank(tanks),
new Jet(jets),
new Fort(forts)
};
}
// The using System.Linq you can do
public int TotalDefense {
get { return Troops.Sum(x=>x.TotalDefense);}
}
}
Although this solution does not use const, it achieves what you want:
internal abstract class Unit
{
private int Count { get; set; }
private int Defense { get; set; }
public int TotalDefense { get { return Count * Defense; } }
protected Unit(int defense, int count)
{
Defense = defense;
Count = count;
}
}
internal class Tank : Unit
{
protected Tank(int count)
: base(5, count) // you can use a const variable instead of 5
{
}
}
Or maybe this is more suitable:
internal abstract class Unit
{
private int Count { get; set; }
public abstract int Defense { get; }
public int TotalDefense { get { return Count * Defense; } }
protected Unit(int count)
{
Count = count;
}
}
internal class Tank : Unit
{
override public int Defense { get { return 5; } }
protected Tank(int count) : base(count)
{
}
}
What you're looking for is actually readonly. Also, since Defense is used in subclasses, you need to make it protected.
private abstract class Unit
{
private int _Count;
protected readonly const int Defense;
public int TotalDefense
{ get { return Count * Defense; } }
protected Unit (int count, int defense)
{
Defense = defense;
_Count = count;
}
}
private class Tank : Unit
{
public Tank (int Count)
: base (Count, 5)
{ }
}
public class Troop
{
public IEnumerable<Unit> Units { get; protected set; }
public Troop (int soldiers, int tanks, int jets, int forts)
{
Troops = new Unit[]
{
new Soldier (soldiers),
new Tank (tanks),
new Jet (jets),
new Fort (forts)
}
}
}
maybe something like this (but this is in java)
abstract class Unit {
Unit(int defense,int count) {
this.defense = defense;
this.count=count;
}
final int defense;
int count;
}
class Soldier extends Unit {
Soldier(int count) {
super(1,count);
}
}
class Tank extends Unit {
Tank(int count) {
super(5,count);
}
}
public class Main {
public static void main(String[] args) {
Unit[] units = { new Soldier(2), new Tank(3) };
for(Unit unit:units)
System.out.println(unit.count+" "+unit.defense);
}
}
I have a base class that does calculations on image sizes. I'm deriving a class from that and have predefined image sizes that will be used in my code. While what I have works, I have a strong feeling that I'm not doing it properly.
Ideally, I'd like to just pass DerviedClass.PreviewSize as the parameter to GetWidth without having to create an instance of it.
class Program
{
static void Main(string[] args)
{
ProfilePics d = new ProfilePics();
Guid UserId = Guid.NewGuid();
ProfilePics.Preview PreviewSize = new ProfilePics.Preview();
d.Save(UserId, PreviewSize);
}
}
class ProfilePicsBase
{
public interface ISize
{
int Width { get; }
int Height { get; }
}
public void Save(Guid UserId, ISize Size)
{
string PicPath = GetTempPath(UserId);
Media.ResizeImage(PicPath, Size.Width, Size.Height);
}
}
class ProfilePics : ProfilePicsBase
{
public class Preview : ISize
{
public int Width { get { return 200; } }
public int Height { get { return 160; } }
}
}
It seems to me that you want a more flexible implementation of ISize - having an implementation which always returns the same value seems fairly pointless. On the other hand, I can see that you want an easy way of getting the size that you always use for a preview. I would do it like this:
// Immutable implementation of ISize
public class FixedSize : ISize
{
public static readonly FixedSize Preview = new FixedSize(200, 160);
private readonly int width;
private readonly int height;
public int Width { get { return width; } }
public int Height { get { return height; } }
public FixedSize(int width, int height)
{
this.width = width;
this.height = height;
}
}
You could then write:
ProfilePics d = new ProfilePics();
Guid userId = Guid.NewGuid();
d.Save(userId, FixedSize.Preview);
This would reuse the same instance of FixedSize whenever you called it.
There are a few ways that you could do this, depending on your needs. I would look at doing a different interface, setup. Something like this.
public interface ISizedPics
{
int Width {get; }
int Height {get; }
void Save(Guid userId)
}
public class ProfilePics, iSizedPics
{
public int Width { get { return 200; } }
public int Height { get { return 160; } }
public void Save(Guid UserId)
{
//Do your save here
}
}
Then, with this done, you could actually work with it like this.
ISizedPics picInstance = new ProfilePics;
Guid myId = Guid.NewGuid();
picInstance.Save(myId);
This is just one way of doing it, I like this way, as you can easily create a factory class around this that helps you declare the instances as needed.