I'm playing with some application and doing a little refactoring in order to make it more flexible. As I expected, a lot of problems arose.
For example i'm trying to find optimal way to delete items from collections in Spaceship class
class Spaceship{
List<Weapon> Weapons {get;set;}
List<Shield> Shields {get;set;}
public void RemoveEquipment(Equipment item){
switch(item.EquipmentType )
{
case EquipmentType.Weapon:
weapons.Remove(item);
break;
case EquipmentType.Shield:
shields.Remove(item);
break;
}
}
public void AddEquipment(Equipment item){
//works the same way as RemoveEquipment
}
}
class Equipment{
//EquipmentType is enum
EquipmentType Type {get;set;};
}
class Weapon: Equipment{
}
class Shield:Equipment{
}
class AutoCannon:Weapon{
}
class LaserGun:Weapon {
}
Is there a better way? What if I want to delete group of items of the same subtype (e.g. every LaserGun in weapons collection - without using reflection)
And if I want to add a new type of Equipment, the methods responsible for adding/deleting have to be modified (switch/case).
As a rule of thumb, you do not want to expose properties of type List, especially if they are not readonly. I would suggest changing the Weapons and Shields properties to either IEnunerable or at the very least IReadOnlyList - and make them readonly.
Having said that, your Spaceship class can look like this:
// internal is the default access modifier for types, but it's more descriptive to specify it.
internal class Spaceship
{
private List<Equipment> _equipment = new List<Equipment>();
public IEnumerable<Weapon> Weapons {get {return _equipment.OfType<Weapon>();}}
public IEnumerable<Shield> Shields {get {return _equipment.OfType<Shield>();}}
public void RemoveEquipment(Equipment item)
{
_equipment.Remove(item);
}
public void AddEquipment(Equipment item)
{
_equipment.Add(item);
}
}
And then, in order to remove all equipments of a specific type, you can do something like this:
public void RemoveEquipment<T>() where T : Equipment
{
_equipment.RemoveAll(e => e is T);
}
You can also add a bunch of equipment at the same time:
public void AddEquipment(IEnumerable<Equipment> items)
{
_equipment.AddRange(items);
}
Note that there are no more cumbersome switch statements and almost nothing involving the specific type of the equipment - except when you explicitly need shields and weapons.
The main benefit, of course, is that when adding a new type of equipment, you don't need to change your Spaceship class to support it (Unless, of course, you want to have a property specialized for that specific type of equipment like Weapons or Shields).
Related
I instantiate my class firedragon. I store it in a public List collection that holds objects.
List<object> currentEnemies = new List<object>();
I want to grab that list item,
currentEnemies[0]
and convert it back into my class. I just don't know how to do that. Can anyone explain to me how to do that, or a better way to store my data?
NOTE: The reason why I am using a list that holds objects is because I have many different classes that may be stored in the list.
One way of handling this is with pattern matching. You could implement a common handler for currentEnemies like,
foreach (var enemy in currentEnemies)
{
switch (enemy)
{
case FireDragon dragon:
UpdateDragon(dragon);
break;
case Bulbasaur plant:
BeAdorable(plant);
break;
// and so on...
}
}
If you have just a handful of types, and won't have much more in the future (consider this carefully), this isn't too bad, but gets horribly cumbersome quickly.
Ideally, you should look for common elements on your enemies, so that you can simplify this. For example, if you have code that moves the enemy in the world every step, they could all implement a common interface,
interface IMobile
{
(int X, int Y) Move(int x, int y);
int Speed { get; }
}
Then code to handle movement of enemies could be just,
var mobiles = new List<IMobile>();
// then in other code that can access `mobiles`
foreach (var mobile in mobiles)
{
mobile.Move(mobile.Speed);
}
Generally it's a bad idea when you have direct control over the items be inserted and removed from a list to use object as the generic type for a List. It sounds like you're building a game, and if you are I would architect it using interfaces and then use OfType<> quite a bit.
// Anything you want to track in the game
public interface IGameEntity {}
// Anything that opposes a plyaer
public interface IEnemy : IGameObject {}
// Anything used to do Physical Harm
public interface IWeapon : IGameObject {}
// Anything that can be collected for a purpose (wood, gold, etc)
public interface IResource : IGameObject {}
I'm honestly not sure if a red dragon would be much different then a blue dragon, I would assume not so I would just create a Dragon class.
public class Dragon : IEnemy
{
public DragonColor Color { get; set; }
}
public enum DragonColor
{
Red,
}
Then you're list is:
List<IGameEntity> entities;
All dragons are
var dragons = entities.OfType<Dragon>();
I have a feeling you are looking for a solution using composition. Example:
public class Enemies {
public FireDragon TheDraggon { get; set; }
public List<Troll> Trolls { get; set; }
/* other enemies that you need to track */
}
With this approach you do not have to guess or check what type an instance is within the list of objects.
I have a business entities as below,
class Class1
{
List<Class2> classes = new List<Class2>();
public IEnumerable<Class2> Classes { get { return classes.AsEnumrable(); }
public void AddClass(Class2 cls)
{
classes.Add(cls);
}
}
class Class2
{
public string Property { get; set; }
}
My business logic requires that once a Class2 instance is added using the AddClass method to the top of the Classes list in Class1, no one should be able to edit the properties of the Class2 instances added previously to the list, only the last item in the list could be edited. How do I do this?
I have tried IReadOnlyList, but it appears that it is concerned with making the list structure itself uneditable without preventing the edit of its items' content.
It's not a container's job to dictate the behavior of its items. A container is just that - an object that contains other objects. An IReadOnlyList is a container whose items cannot be modified. But the items within it are jsut Class2 instances - there's nothing that the container can do to prevent them from being edited.
Consider this:
myReadOnlyCollection[0].Property = "blah";
var firstItem = myReadOnlyCollection[0];
firstItem.Property = "blah";
Should this be legal in your scenario? What's the difference between the two? firstItem is simply an instance of Class2 that has no idea it was once inside a read-only collection.
What you need is for Class2 itself to be immutable. That's up to the class, not the container. Read up on immutability, which is an important concept to grasp, and implement Class2 accordingly. If you need a regular, mutable Class2 to change its behavior, perhaps add a ToImmutable() method to it which returns a different item, without a setter.
Why are you exposing the IReadOnlyCollection. Once you have exposed the objects, the objects themselves have to be immutable.
Why not just expose the only object that you want to expose?
private IEnumerable<Class2> Classes { get { return classes; }
public Class2 Class2Instance { get { return classes.Last(); } }
I can only see three options. One is to alter Class2 to make it lockable and then lock it once it's added to your list...
class Class1 {
List<Class2> classes = new List<Class2>();
public IEnumerable<Class2> Classes {
get { return classes.AsEnumrable();
}
public void AddClass(Class2 cls) {
cls.Lock();
classes.Add(cls);
}
}
class Class2 {
private string _property;
private bool _locked;
public string Property {
get { return _property; }
set {
if(_locked) throw new AccessViolationException();
_property = value;
}
}
public void Lock() {
_locked = true;
}
}
Another option is to only return the values of the list objects instead of the objects themselves...
class Class1 {
List<Class2> classes = new List<Class2>();
public IEnumerable<string> Values {
get { return classes.Select(cls => cls.Property); }
}
public void AddClass(Class2 cls) {
classes.Add(cls);
}
}
In this second method, anything other than a single value and you'll need to either return a tuple. Alternately, you could create a specific container for Class2 that exposes the values as read-only...
class Class2ReadOnly {
private Class2 _master;
public Class2ReadOnly(Class2 master) {
_master = master;
}
public string Property {
get { return _master.Property; }
}
}
class Class1 {
List<Class2ReadOnly> classes = new List<Class2ReadOnly>();
public IEnumerable<Class2ReadOnly> Classes {
get { return classes.AsEnumerable(); }
}
public void AddClass(Class2 cls) {
classes.Add(new Class2ReadOnly(cls));
}
}
I know it is an old problem, however I faced the same issue today.
Background: I want to store data in my application, e.g. users can set their custom objects in the project and the Undo-redo mechanism must be adapted to handle batched data storing.
My approach:
I created some interfaces, and I made a wrapper for the collection I don't want the users to modify.
public class Repository : IRepository
{
// These items still can be changed via Items[0].CustomProperty = "asd"
public readonly List<CustomItem> Items { get; }
private readonly List<CustomItem> m_Originaltems;
//However, when I create RepositoryObject, I create a shadow copy of the Items collection
public Repository(List<CustomItem> items)
{
items.ForEach((item) =>
{
// By cloning an item you can make sure that any change to it can be easily discarded
Items.Add((CustomItem)item.Clone());
});
// As a private field we can manage the original collection without taking into account any unintended modification
m_OriginalItems = items;
}
// Adding a new item works with the original collection
public void AddItem(CustomItem item)
{
m_OriginalItems.Add(item);
}
// Of course you have to implement all the necessary methods you want to use (e.g. Replace, Remove, Insert and so on)
}
Pros:
Using this approach you basically just wraps the collection into a custom object. The only thing you expect from the user side is to have ICloneable interface implemented.
If you want, you can make your wrapper generic as well, and give a constraint like where T : ICloneable
Cons:
If you add new items, you won't know about them by checking the Items property. A workaround can be done by creating a copy of the collection whenever Items.get() is called. It is up to you and your requirements.
I meant something like this:
public class Repository : IRepository
{
public List<CustomItem> Items => m_OriginalItems.Select(item => (CustomItem)item.Clone()).ToList();
private readonly List<CustomItem> m_Originaltems;
public Repository(List<CustomItem> items)
{
m_OriginalItems = items;
}
public void AddItem(CustomItem item)
{
m_OriginalItems.Add(item);
}
// Of course you still have to implement all the necessary methods you want to use (e.g. Replace, Count, and so on)
}
As other said, it is not the collections job to dictate if (and how) you access it's elements. I do see ways around this:
Exceptions & references:
Modify Class2 so it can take a reference to Class1. If the reference is set, throw excetpions on all setters. Modify Class1.AddClass to set that property.
A softer version of this would be a "read only" property on Class2, that all other code has to check.
Readonly Properties & Constructors:
Just always give Class2 readonly properties (private set). If you want to define the property values, you have to do that in the constructor (which has proper Arguments). This pattern is used heavily by the Exception classes.
Inheritance Shenanigans:
Make Multiple Class2 versions in an inheritance chain, so that that Class2Writebale can be cast to a Class2ReadOnly.
Accept the wrong Y:
You might have stuck yourself into a XY problem: https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem
If so go a step back to fix it.
I don't really know how to formulate my issue it's a bit complicated for me, i'll try my best to explain.
I'm making a space game, i have a base class which represent places, and i want to have different type of places like planets, space stations, asteroïds, trading ships etc. The player can click on those objects and get informations.
So my classes looks like something like this:
public class Place {
public int placeId;
public string placeName;
public string placeDescription;
/* Place constructor */
}
public class Planet : Place {
/* Specific proprieties of planet */
public PlanetType planetType;
public int planetSize;
...
// Planet constructor
public Planet(int placeId, string placeName, string placeDescription, PlanetType planetType, int planetSize) : base(placeId, placeName, placeDescription) {
this.planetType = planetType;
this.planetSize = planetSize;
...
}
}
And i have a delegate which accept a function like selectPlace with Place in parameters because i don't want to make a delegate for each type of Place i have.
In another script which is supposed to show the information of any kind of Place, i recieves the Place object that the player clicked on. I think i found a solution, however is this correct to do something like this ?
private void updateSelectedPlaceUI(object sender, EventsController.PlaceEventArgs placeArgs){
// This is just a test, i should check which type of subclass it is before
Planet planetTest = placeArgs.Place as Planet; // So now i can use planetTest.planetType
}
And placing this in a switch case so i can handle any type. I just want to be able to get the proprieties from any derived class of Place in order to display them in UI. I would like to know a better way to achieve this.
But i'm wondering if my design is ok and necessary, it has been a while since i haven't used inheritance / polymorphism, and i feel like i'm doing it the wrong way.
I would propably make the UI part of showing the properties a specific place generic to accept something like a PropertyItem, you can decide the properties yourself.
public class PropertyItem
{
public string Text { get; set; }
public object Value { get; set; }
}
And then in your select method you would just call the abstract method of your base class (make your base class abstract as well)
public abstract class Place
{
...
public abstract IEnumerable<PropertyItem> GetProperties();
}
And now you can override this in your Planet
public class Planet : Place
{
...
public override IEnumerable<PropertyItem> GetProperties()
{
yield return new PropertyItem { Text = "Size", Value = this.planetSize };
}
}
And eventually you would use the GetProperties() method to get the properties of your place and show them in a tabular or what ever format your UI knows how to handle the PropertyItem type.
private void updateSelectedPlaceUI(object sender, EventsController.PlaceEventArgs placeArgs)
{
MyUserInterfaceWidget.DisplayProperties(placeArgs.Place.GetProperties());
}
Say we have a class Potato (and instances therefore) that has an attribute smoothness which is used for other method but is not pretended to be public. This attribute is setted when the instance is created and is used only internally the instance.
Moreover, my system should support several database drivers, therefore I have an interface "databse adaptor" that will be instantiated with the class which uses the driver I want to use at the moment.
Now comes the problem. I need to make the object(the potato) persistent and save it into a database, therefore I should save the smoothness of our potato by using the database adaptor class, but.. it's private!
How can I send the smoothness of the potato without making it accessible for other purposes?
Thanks in advance
Write a method that allows the object to save itself, taking a writer of some kind as a parameter. Since this is a database, you might need to have both Insert and Update methods, instead of just a Save method. You might put these into an interface as well.
rough example:
public interface IDatabaseSaveable
{
void InsertToDatabase(Database pDatabase);
void UpdateDatabase(Database pDatabase);
}
public class Potato : IDatabaseSaveable
{
private int mID;
private double mSmoothness;
public void InsertToDatabase(Database pDatabase)
{
pDatabase.InsertToPotatoes(mID, mSmoothness, ...);
}
public void UpdateDatabase(Database pDatabase)
{
pDatabase.UpdatePotatoes(mID, mSmoothness, ...);
}
}
You can create an importer/exporter interface pair that externalize the "state" of the Potato without giving access to its implementation details (in this case, its private members and data types). They are types of builders.
public class Potato {
public interface IExporter {
void AddSmoothness(string value);
}
public interface IImporter {
string ProvideSmoothness();
}
public Potato(IImporter importer) {
this.smoothness = int.Parse(importer.ProvideSmoothness());
}
public void Export(IExporter exporter) {
exporter.AddSmoothness(this.smoothness.ToString());
}
public Potato(int smoothness) {
this.smoothness = smoothness;
}
private int smoothness;
}
Then, your database adapter classes will implement the relevant interfaces and use the corresponding methods. Look here for the original idea.
This is a variation on having a smoothness property marked as internal. Assuming that potato must have a smoothness set before you can use it, an internal constructor might be better. I'm going to accept on faith that there's a good reason to hide smoothness. Modesty on the part of the potato, perhaps?
public class Potato
{
internal int Smoothness { get; set; }
internal Potato(int smoothness)
{
this.Smoothness = smoothness;
}
private Potato() { }
}
Only classes in the same assembly will be able to instantiate a Potato using the internal constructor. And only classes in the same assembly will be able to access Smoothness (so they can save the potato.)
I previously posted this, but I guess it was too verbose and irrelevant. My question is also like this. One poster in the second link said the answer (of why you can't do the code below) was a problem of design, specifically "bad use of inheritance". So I'd like to check this issue again with the experts at StackOverflow and see if this is really an issue of "bad inheritance" - but more importantly, how to fix the design.
Like the poster, I'm also confused about the Factory method and how I can apply it. It seems the factory method is for multiple concrete classes that have the exact same implementation as the abstract base class and do not add their own properties. But, as you will see below, my concrete classes build upon the abstract base class and add extra properties.
The Base Class We Build Upon:
public abstract class FlatScreenTV
{
public string Size { get; set; }
public string ScreenType { get; set; }
}
Extension Class Examples:
public class PhillipsFlatScreenTV : FlatScreenTV
{
// Specific to Phillips TVs. Controls the backlight intensity of the LCD screen.
public double BackLightIntensity { get; set; }
}
public class SamsungFlatScreenTV : FlatScreenTV
{
// Specific to Samsung TVs. Controls the time until the TV automatically turns off.
public int AutoShutdownTime { get; set; }
}
Let's say there are more extension classes for more brands of flat screen TVs. And then, let's say we stick them all into a generic List:
public static void Main()
{
List<FlatScreenTV> tvList = new List<FlatScreenTV>();
tvList.Add(new PhillipsFlatScreenTV());
tvList.Add(new SamsungFlatScreenTV());
tvList.Add(new SharpFlatScreenTV());
tvList.Add(new VizioFlatScreenTV());
FlatScreenTV tv = tvList[9]; // Randomly get one TV out of our huge list
}
The Problem:
I want to access the specific properties of whatever 'original' brand TV this variable belongs to. I know the brand because if I call tv.GetType(), it returns the correct 'original' type - not FlatScreenTV. But I need to be able to cast tv from FlatScreenTV back to its original type to be able to access the specific properties of each brand of flat-screen TVs.
Question #1: How can I dynamically cast that, properly - without makeshift hacks and huge if-else chains to brute-guess the 'original' type?
After browsing around similar design issues, most answers are: you can't. Some people say to look at the Factory Pattern, and others say to revise the design using interfaces, but I don't know how to use either to solve this problem.
Question #2: So, how should I design these classes so that I can access the original type's specific properties in the context above?
Question #3: Is this really bad inheritance?
Your design violates the "Liskov Substitution Principle". In other words, the code that deals with items from your list of FlatScreenTV shouldn't know or care what derived type is.
Say your code needs to create a custom remote control GUI. It might be enough to simply know the names and types of the properties of each TV to auto-generate the UI. In which case you could do something like this to expose the custom properties from the base class:
public abstract class FlatScreenTV
{
public FlatScreenTV()
{
CustomProperties = new Dictionary<string,object>();
}
public Dictionary<string,object> CustomProperties { get; private set; }
public string Size { get; set; }
public string ScreenType { get; set; }
}
public class PhillipsFlatScreenTV : FlatScreenTV
{
public PhillipsFlatScreenTV()
{
BackLightIntensity = 0;
}
// Specific to Phillips TVs. Controls the backlight intensity of the LCD screen.
public double BackLightIntensity
{
get { return (double)CustomProperties["BackLightIntensity"]; }
set { CustomProperties["BackLightIntensity"] = value; }
}
}
public class SamsungFlatScreenTV : FlatScreenTV
{
public SamsungFlatScreenTV()
{
AutoShutdownTime = 0;
}
// Specific to Samsung TVs. Controls the time until the TV automatically turns off.
public int AutoShutdownTime
{
get { return (int)CustomProperties["AutoShutdownTime"]; }
set { CustomProperties["AutoShutdownTime"] = value; }
}
}
If you really do need to be working directly with the derived types, then you should instead consider moving to a plugin based architecture. For example, you might have a factory method like this:
IRemoteControlGUI GetRemoteControlGUIFor(FlatScreenTV tv)
which would scan your plugins and find the one that knew how to build the UI for the particular type of FlatScreenTV you passed in. This means that for every new FlatScreenTV you add, you also need to create a plugin that knows how to make its remote control GUI.
Factory Pattern would be the best way to go
I can offer a partial answer:
Firstly read up on Liskov's Substitution Principle.
Secondly you are creating objects that inherit from FlatScreenTV, but apparently for no purpose as you want to refer to them by their SubType (SpecificTVType) and not their SuperType (FlatScreenTV) - This is bad use of Inheritance as it is NOT using inheritance lol.
If your code wants to access properties particular to a given type, then you really want this code encapsulated within that type. Otherwise everytime you add a new TV type, all the code that handles the TV list would need to be updated to reflect that.
So you should include a method on FlatScreenTV that does x, and override this in TV's as required.
So basically in your Main method above, instead of thinking I want to be dealing with TVTypeX, you should always refer to the basetype, and let inheritance and method overriding handle the specific behaviour for the subtype you are actually dealing with.
Code eg.
public abstract class FlatScreenTV
{
public virtual void SetOptimumDisplay()
{
//do nothing - base class has no implementation here
}
}
public class PhilipsWD20TV
{
public int BackLightIntensity {get;set;}
public override void SetOptimumDisplay()
{
//Do Something that uses BackLightIntensity
}
}
"the factory method is for multiple concrete classes that have the exact same implementation as the abstract base class [interface] and do not add their own properties."
No, speaking more practical, than theorical, the factory method can provide you with objects of concrete classes, in which the concrete classes, must have some common methods and interfaces, but, also some additional specific attributes.
Sometimes I use a method that creates the same class object every time I called, and I need to call it several times, and sometimes I use a method that create several different class objects, and that maybe be confusing, maybe another question.
And, your further comment about a switch sentence, with many options, when using the factory pattern, you usually provide an identifier for the concrete class / concrete object. This can be a string, an integer, an special type id, or an enumerated type.
You could use an integer / enum ID instead, and use a collection to lookup for the concrete class.
You can still leverage a factory. The point of a factory IMO is to put all the heavy lifting of constructing your various TVs in one place. To say categorically "a factory is for multiple concrete classes that have the exact same implementation as the abstract base class" is forgetting about polymorphism.
There is no law that says you cannot use a factory pattern because the sub classes declare unique properties and methods. But the more you can make use of polymorphism, the more a factory pattern makes sense. Also as a general guideline, IMHO, the more complexity that must go into constructing from the base the better off you are in the long run using a factory because you are "encapsulating change" - that is, constructing concrete classes is likely to change due to differing requirements and inherent construction complexity (a design analysis decision, to be sure) . And that change is in a single class - the factory.
Try this: Define everything in the abstract class and then for a given TV subclass either write concrete-specific code, and for those that don't apply write some standard "I don't do that" code.
Think about all the things your TVs do in generic terms: turn on, turn off, etc. Write a virtual method shell in the base class for all the generic things a TV does - this is a simple example of the template method pattern by the way. Then override these in the concrete classes as appropriate.
There are other things you can do in the base class to make it more fundgeable (that's a technical term meaning "reference subclasses as the base class, but do sub-classy things").
Define delegate methods (very powerful yet under-utilized)
use params[] for dynamic method parameter lists
Make Property delegates
Static methods
Declare Properties and methods "abstract" - forces sub-class implementation, vis-a-vis "virtual"
Hide inherited stuff in the sub class (generally using "new" keyword to communicate that it's on purpose)
If construction parameters are numerous or complex, create a class specifically designed to pass configuration to the factory's build method.
public class TVFactory {
public TV BuildTV(Brands thisKind) {
TV newSet;
switch (thisKind) {
case Brands.Samsung :
Samsung aSamsungTV = new Samsung();
aSamsungTV.BacklightIntensity = double.MinVal;
aSamsungTV.AutoShutdownTime = 45; //oops! I made a magic number. My bad
aSamsungTV.SetAutoShutDownTime = new delegate (newSet.SetASDT);
newSet = aSamsungTV;
break;
. . .
} // switch
}
//more build methods for setting specific parameters
public TV BuildTV (Brands thisKind, string Size) { ... }
// maybe you can pass in a set of properties to exactly control the construction.
// returning a concrete class reference violates the spirit of object oriented programming
public Sony BuildSonyTV (...) {}
public TV BuildTV (Brands thisKind, Dictionary buildParameters) { ... }
}
public class TV {
public string Size { get; set; }
public string ScreenType { get; set; }
public double BackLightIntensity { get; set; }
public int AutoShutdownTime { get; set; }
//define delegates to get/set properties
public delegate int GetAutoShutDownTime ();
public delegate void SetAutoShutDownTime (object obj);
public virtual TurnOn ();
public virtural TurnOff();
// this method implemented by more than one concrete class, so I use that
// as an excuse to declare it in my base.
public virtual SomeSonyPhillipsOnlything () { throw new NotImplementedException("I don't do SonyPhillips stuff"); }
}
public class Samsung : TV {
public Samsung() {
// set the properties, delegates, etc. in the factory
// that way if we ever get new properties we don't open umpteen TV concrete classes
// to add it. We're only altering the TVFactory.
// This demonstrates how a factory isolates code changes for object construction.
}
public override void TurnOn() { // do stuff }
public override void TurnOn() { // do stuff }
public void SamsungUniqueThing () { // do samsung unique stuff }
internal void SetASDT (int i) {
AutoShutDownTime = i;
}
}
// I like enumerations.
// No worries about string gotchas
// we get intellense in Visual Studio
// has a documentation-y quality
enum Brands {
Sony
,Samsung
,Phillips
}