Help with building object model - c#

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);
}
}

Related

Generic class<T> with constructor to choose the type

I have three classes that have all the same named Properties. Let's say the classes are Sword, Bow and Hammer -- and the properties are Damage and Range. How could I instantiate a class of Weapon<T> with a constructor where I pass an int to choose the Type of this class?
I am not sure if this is even the right way to do what I want to.
public class Weapon<T>
{
}
public class Sword
{
public int Damage { get => 10; }
public int Range { get => 12; }
}
public class Bow
{
public int Damage { get => 8; }
public int Range { get => 28; }
}
public class Hammer
{
public int Damage { get => 15; }
public int Range { get => 8; }
}
What you´ve described is known as factory-pattern. You have some factory that is able to instantiate other objects, in your case depending on an integer:
class WeaponFactory
{
public static IWeapon CreateWeapon(WeaponType type)
{
switch type:
case WeaponType.Sword: return new Sword();
case WeaponType.Hammer: return new Hammer();
case WeaponType.Bow: return new Bow();
default: throw new ArgumentException("Unknown weaponType");
}
}
enum WeaponType { Sword, Hammer, Bow }
interface IWeapon
{
int Damage { get; }
int Range { get; }
}
Finally all your classes should implement that interface. Now you can easily create instances with the following code:
var hammer = WeaponFactory.CreateWeapon(WeaponType.Hammer);
I'd simplify this beyond what you have and also beyond the other solutions proposed.
public class Weapon
{
private int _range;
private int _damage;
public Weapon(int range, int damage)
{
_range = range;
_damage = damage;
}
public int Range => _range;
public int Damage => _damage;
}
There's no real need for polymorphism here - all you want to do is assign different readonly values at runtime. If you later want differing behaviour per weapon, you can achieve that with the strategy pattern.
I'd then just use factories to instantiate different weapons.
What those factories looked like would depend on how they need to be called but in practice your factory method could look something like this:
public Weapon GetWeapon(string weaponType)
{
var weaponProperties = propertiesFor(weaponType);
return new Weapon(weaponProperties.Range, weaponProperties.Damage);
}
Where propertiesFor looks up the appropriate values for the given weapon type in a dictionary, file etc. etc.
I would steer clear of an IWeapon interface unless you really need to supply different implementations of weapons at runtime. Don't write it 'til you need it. Declaring an interface just for the purposes of mocking in tests (as some others have suggested) would normally indicate to me that your test boundaries are off or you have some dependencies to isolate better (but that's a broader conversation).
public interface IWeapon
{
int Damage { get; }
int Range { get; }
}
public class Weapon : IWeapon
{
protected int _damage, _range;
public int Damage
{
get { return _damage; }
}
public int Range
{
get { return _range; }
}
}
public class Sword : Weapon
{
public Sword()
{
_damage = 10;
_range = 12;
}
}
public class Bow : Weapon
{
public Bow()
{
_damage = 8;
_range = 28;
}
}
public class Hammer : Weapon
{
public Hammer()
{
_damage = 15;
_range = 8;
}
}
Inherit from a base class
public class Weapon
{
public int Damage { get; set; }
public int Range { get; set; }
}
public class Sword : Weapon
{
}
public class Bow : Weapon
{
}
public class Hammer : Weapon
{
}
and instanciate this way
Weapon item = new Sword() { Damage = 10, Range = 20 };
You could start by creating interface for parent weapon class. Then extend weapon class with child classes to make swords, hammers and etc... Then you can add custom properties for each child class and still use them as weapon because they all share same interface/parent class and they all have attack method...
public interface IWeapon
{
int Damage { get; }
int Range { get; }
void Attack();
}
public class Weapon : IWeapon
{
public int Damage { get; private set; }
public int Range { get; private set; }
public Weapon(int damage, int range)
{
Damage = damage;
Range = range;
}
public virtual void Attack()
{
Console.WriteLine("Weapon: Attack");
}
}
public class Sword : Weapon
{
//some sword properties here...
public Sword(int damage, int range) : base(damage, range)
{
}
public override void Attack()
{
Console.WriteLine("Weapon Sword: Attack");
}
}
public class Bow : Weapon
{
//some bow properties here...
public Bow(int damage, int range) : base(damage, range)
{
}
public override void Attack()
{
Console.WriteLine("Weapon Bow: Attack");
}
}
public class Hammer : Weapon
{
//some hammer properties here...
public Hammer(int damage, int range) : base(damage, range)
{
}
public override void Attack()
{
Console.WriteLine("Weapon Hammer: Attack");
}
}
class Program
{
public static void Main(string[] args)
{
IWeapon hammerWeapon = new Hammer(15, 10);
hammerWeapon.Attack();
}
}

Change a static variable in a subclass without changing it in the parent class

I want that a.ID() returns 0 and b.ID() returns 1 and here is my code:
public class A {
public static int id;
public int ID() {return id;}
}
public class B : A { }
public class Main {
void Program() { //This executes when I execute the program
A.id = 0;
B.id = 1;
}
}
But it doesn't work, this also doesn't work:
public class A {
public static int id;
public int ID() {return id;}
}
public class B : A {
public new static int id; //id is actually 1 but ID() is still 0
}
public class Main {
void Program() { //This executes when I execute the program
A.id = 0;
B.id = 1;
}
}
How can I fix this?
You can create two static variables and one virtual property
public class A
{
private static int _idA;
public virtual int Id
{
get { return _idA; }
set { _idA = value; }
}
}
public class B : A
{
private static int _idB;
public override int Id
{
get { return _idB; }
set { _idB = value; }
}
}
Or one property and use new keyword to override it
public class A
{
public static int Id { get; set; }
}
public class B : A
{
public static new int Id { get; set; }
}
To test first solution you can try following
static void Main(string[] args)
{
A test = new B();
new B().Id = 3;
new A().Id = 2;
test.Id = 1;
Console.WriteLine(test.Id + " " + new B().Id + " " + new A().Id);
Console.ReadKey();
}
If you can accept these rules:
The numbers can be anything, ie. any legal int
They don't have to start at 0
They don't have go up by 1 for each new unique type
The numbers are allowed to change between executions of your program
ie. you run your program and type A returns id 33554436
You change the program (somewhere else) and rerun, now type A returns id 33554437 (a different value)
then here is a way to get your ID:
public class Base
{
public int ID
{
get
{
return GetType().MetadataToken;
}
}
}
You don't need to override this property to get unique id's for each type but you can no longer guarantee what the values will be, here's example output from two such derived classes:
33554436
33554437
If I added a new type between those two and reran, I got:
33554436
33554438
If you're afraid the constant trip to reflection is going to be expensive here is an alternative declaration:
public class Base
{
private readonly Lazy<int> _ID;
protected Base()
{
_ID = new Lazy<int>(() => GetType().MetadataToken);
}
public int ID
{
get
{
return _ID.Value;
}
}
}
You can make the ID method virtual and override it in the B class like this:
public class A
{
public static int id;
public virtual int ID() { return id; }
}
public class B : A
{
public static int id;
public override int ID()
{
return id;
}
}
Here is another way to do it that uses Reflection:
public class A
{
public static int id;
public int ID()
{
return (int)this.GetType()
.GetField("id", BindingFlags.Static | BindingFlags.Public)
.GetValue(null);
}
}
public class B : A
{
public static int id;
}
This way, you don't have to override the ID method on each subclass. However, you still need to defined a static id field in each subclass.

Polymorphism and Interfaces in C#

Create three small classes unrelated by inheritance—classes Building, Car and Bicycle. Write an interface ICarbonFootprint with a GetCarbonFootprint method. Have each of your classes implement that interface, so that its GetCarbonFootprint method calculates an appropriate carbon footprint for that class (check out a few websites that explain how to calculate carbon footprints). Write an app that creates objects of each of the three classes, places references to those objects in List, then iterates through the List, polymorphically invoking each object’s GetCarbonFootprint method. Constructor of Car initialize “gallon of gas”, and the Building constructor will initialize buiding-square-footage.
how to calculate carbon-footprint
One gallon of gas yields 20 pounds of CO2 for a car
Multiply the square footage by 50 for a building
None for a bicycle
My instructor's code:
public static void Main(string[] args)
{
ICarbonFootprint[] list = new ICarbonFootprint[3];
// add elements to list
list[0] = new Bicycle();
list[1] = new Building(2500);
list[2] = new Car(10);
// display carbon footprint of each object
for (int i = 0; i < list.Length; i++)
list[i].GetCarbonFootprint();
} // end Main
}
My code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Miller
{
class Program
{
static void Main(string[] args)
{
Bicycle bike = new Bicycle();
Building b = new Building();
Car car = new Car();
List<ICarbonFootprint> list = new List<ICarbonFootprint>();
list.Add(bike);
list.Add(b);
list.Add(car);
int totalCarbon = 0;
foreach (var item in list)
{
totalCarbon += item.GetCarbonFootprint();
Console.WriteLine("{0} has a footprint of: {1}", item, item.GetCarbonFootprint());
}
Console.WriteLine("Total footprint is: {0}", totalCarbon);
Console.ReadKey();
}
}
public class Bicycle : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 10;
}
public override string ToString()
{
return string.Format("Bike");
}
}
public class Building : ICarbonFootprint
{
private string _address;
public string Address
{
get { return _address; }
set { _address = value; }
}
public int GetCarbonFootprint()
{
return 2000;
}
public override string ToString()
{
return string.Format("Building");
}
}
public class Car : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 1500;
}
public override string ToString()
{
return string.Format("Car");
}
}
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
}
Me integrating my instructor's code (lines 12-23 changed AKA class Program was the only thing changed):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Miller
{
class Program
{
public static void Main(string[] args)
{
ICarbonFootprint[] list = new ICarbonFootprint[3];
// add elements to list
list[0] = new Bicycle();
list[1] = new Building(2500);
list[2] = new Car(10);
// display carbon footprint of each object
for (int i = 0; i < list.Length; i++)
list[i].GetCarbonFootprint();
} // end Main
}
public class Bicycle : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 10;
}
public override string ToString()
{
return string.Format("Bike");
}
}
public class Building : ICarbonFootprint
{
private string _address;
public string Address
{
get { return _address; }
set { _address = value; }
}
public int GetCarbonFootprint()
{
return 2000;
}
public override string ToString()
{
return string.Format("Building");
}
}
public class Car : ICarbonFootprint
{
private string _make;
private string _model;
public string Make
{
get { return _make; }
set { _make = value; }
}
public string Model
{
get { return _model; }
set { _model = value; }
}
public int GetCarbonFootprint()
{
return 1500;
}
public override string ToString()
{
return string.Format("Car");
}
}
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
}
So, replacing my code for class Program with my instructor's code, I received the following errors:
Program.cs(51,23,51,41): error CS1729: 'Miller.Building' does not contain a constructor that takes 1 arguments
Program.cs(52,23,52,34): error CS1729: 'Miller.Car' does not contain a constructor that takes 1 arguments
Now, because the last two days before Spring break were cancelled due to the weather (snow), we weren't able to discuss. My code seems to do what the directions ask, but I would like to get my instructor's code for class Program working with my code. Could someone help me with these errors possibly?
There are a few issues with your code.
First up you need to include the constructors to make the code compile.
For Building this would look like:
private int squareFootage;
public Building(int squareFootage)
{
this.squareFootage = squareFootage;
}
And for Car this would look like:
private int gasGallons;
public Car(int gasGallons)
{
this.gasGallons = gasGallons;
}
Next, you're not following the rules for calculating the carbon footprint.
They should be:
//Bicycle
public int GetCarbonFootprint()
{
return 0;
}
//Building
public int GetCarbonFootprint()
{
return 50 * squareFootage;
}
//Car
public int GetCarbonFootprint()
{
return 20 * gasGallons;
}
Finally, your instructor's code doesn't actually display any results. The code in the for loop should be changed to be Console.WriteLine(list[i].GetCarbonFootprint()); if this is a console app.
So, all up the code should look like this:
public static void Main(string[] args)
{
ICarbonFootprint[] list = new ICarbonFootprint[3];
// add elements to list
list[0] = new Bicycle();
list[1] = new Building(2500);
list[2] = new Car(10);
// display carbon footprint of each object
for (int i = 0; i < list.Length; i++)
Console.WriteLine(list[i].GetCarbonFootprint());
}
public class Bicycle : ICarbonFootprint
{
public string Make { get; set; }
public string Model { get; set; }
public int GetCarbonFootprint()
{
return 0;
}
}
public class Building : ICarbonFootprint
{
private int squareFootage;
public Building(int squareFootage)
{
this.squareFootage = squareFootage;
}
public string Address { get; set; }
public int GetCarbonFootprint()
{
return 50 * squareFootage;
}
}
public class Car : ICarbonFootprint
{
private int gasGallons;
public Car(int gasGallons)
{
this.gasGallons = gasGallons;
}
public string Make { get; set; }
public string Model { get; set; }
public int GetCarbonFootprint()
{
return 20 * gasGallons;
}
}
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
I've opted to short-cut the property definitions rather than implement them with fields.
The output is:
0
125000
200
You should write constructors for Building and Car like next:
public Building(int MyValue)
{
...
}
and your code will work fine.
Suggestion: Car and Bicycle shares properties, and the ICarbonFootprint implementation, so you can create a base class with an abstract method. Also the GetCarbonFootprint from ICarbonFootprint interface must be type of System.Double.
public interface ICarbonFootprint
{
int GetCarbonFootprint();
}
public class Building : ICarbonFootprint
{
public int BuildingSquareFootage { get; set; }
public string Address { get; set; }
public Building(int buildingSquareFootage, string address)
{
BuildingSquareFootage = buildingSquareFootage;
Address = address;
}
public int GetCarbonFootprint()
{
return BuildingSquareFootage * 50;
}
public override string ToString()
{
return string.Format("Building");
}
}
public abstract class CarBicycleBase : ICarbonFootprint
{
public string Make { get; set; }
public string Model { get; set; }
protected CarBicycleBase(string make, string model)
{
Make = make;
Model = model;
}
public abstract int GetCarbonFootprint();
}
public class Bicycle : CarBicycleBase
{
public Bicycle(string make, string model)
: base(make, model) { }
public override int GetCarbonFootprint()
{
return 0;
}
public override string ToString()
{
return string.Format("Bike");
}
}
public class Car : CarBicycleBase
{
public int GallonOfGas { get; set; }
public Car(int gallonOfGas, string make, string model)
: base(make, model)
{
GallonOfGas = gallonOfGas;
}
public override int GetCarbonFootprint()
{
return GallonOfGas * 20;
}
public override string ToString()
{
return string.Format("Car");
}
}
Example:
...
var list = new List<ICarbonFootprint>(3)
{
new Car(10, "...", "..."),
new Bicycle("...", "..."),
new Building(20, "...")
};
foreach (ICarbonFootprint item in list)
item.GetCarbonFootprint();
...
I hope it helps.

Inheritance solution

I've been working on building several classes which inherit from one base class but I'm not entirely confident on how inheritance and polymorphism work in C# at this stage.
My base class looks like this:
abstract class Structure
{
public int currentCost = 0;
public int currentArea = 0;
public int currentPopulation = 0;
public int currentConstruction = 0;
public int currentEnergy = 0;
public int currentEconomy = 0;
public abstract int baseCost { get; }
public abstract int baseEnergy { get; }
public abstract int baseEconomy { get; }
public abstract int baseConstruction { get; }
public int baseArea = -1;
public int basePopulation = -1;
public int level = 0;
public abstract string structureName { get; }
}
Now, classes that inherit from the Structure class will be made to provide their own assignments for the abstract variables which is fine as most of the classes vary wildly in the figures they assign.
The abstract variables are used in the derived classes in the following (incomplete) manner:
class BiosphereModification : Structure
{
const int baseEconomyBiosphereModification = 0;
const int baseConstructionBiosphereModification = 0;
const int baseCostBiosphereModification = 2000;
const int baseEnergyBiosphereModification = 0;
const int baseFertilityBiosphereModification = 1;
const string structureNameBiosphereModification = "BiosphereModification";
public override int baseCost { get { return baseCostBiosphereModification; } }
public override int baseEconomy { get { return baseEconomyBiosphereModification; } }
public override int baseEnergy { get { return baseEnergyBiosphereModification; } }
public override int baseConstruction { get { return baseConstructionBiosphereModification; } }
}
However, the non-abstract variables will be the same across the majority of derived classes, but not all of them.
I could make them all abstract and force each class to provide it's own value, but this seems counter-intuitive. What I would prefer is a way to provide a value in the base class and provide an override in a derived class if needed.
Is there a way to do this? I know that this can be done with methods declared virtual. This allows the derived class to use the base classes method unless it provides one of it's own. Surely a similar thing exists for this?
What I would prefer is a way to provide a value in the base class and provide an override in a derived class if needed.
Properties can be declared virtual, as well:
public virtual int BaseCost { get { return 0; } }
public virtual int BaseEnergy { get { return 42; } }
public virtual int BaseEconomy { get { return 3982; } }
public virtual int BaseConstruction { get { return 398829; } }
You can then override them when appropriate:
public override int BaseCost { get { return 2; } }

C#: Pass derived class as parameter

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.

Categories