Share functionality between two classes - c#

This question sounds very common, but I have no idea how i should implement it.
My scenario:
Question: How to implement DirectionTile?
Behavior implementation of DirectionTile:
abstract class DirectionTile
{
public Point Direction;
public Tile Next => Board.GetTile(Coords + Direction);
}
As you can see property Coords will be from the base class (?), which is Tile.
Both RailTile and SailTile are DirectionTiles. However, I can not just inherit from DirectionTile, as SailTile needs to inherit from WaterTile and this would case 2 relations with Tile (really want to use polymorphism like this).
I hope somebody can help me with this problem, that I can not solve. Let me know if my explanation is clear enough.

If i understand correctly, DirectionTile is a behaviour implemented by entity.
Use simply an Interface IDirectionTile, and to prevent multiple implementation you could provide an extension Methods :
public interface IDirectionTile
{
}
public static class TileExtensions
{
public static void GetDirection(this IDirectionTile th)
{
}
public static void Next(this IDirectionTile th)
{
}
}

Do it like this: Base from your diagram Tile will be your base/parent class and all other classes will be its child class. which then will inherit the property and function(s) that the Tile has. For DirectionTile i think it's a separate entity/class where you will just instantiate WaterTile and RailTile
public abstract class Tile
{
private Point direction;
public Point Direction
{
get { return direction; }
set { direction = value; }
}
public abstract string someFunction();
}
Now to inherit the property and the function:
public class WaterTile : Tile
{
//all property and functions now are accessible from the Tile base class
private string somevariable;
public string Somevariable
{
get{return somevariable;}
set{somevariable=value;}
}
public override string someFunction()
{
//return "something";
}
}
public class SailTile : WaterTile
{ //if there are additional properties/functions in your WaterTile it will be accessible by this class (SailTile) but not to other class
//in this case Somevariable is accessible in this class
}

Related

Should I upcast before calling an inherited method

I am probably doing something way wrong here, but I have a Base class with multiple derived classes.
public abstract class BaseItem : MonoBehaviour
{
public void LevelUp()
{
// do some common thing ... maybe increase damage
}
}
public class RangedWeapon: BaseItem
{
public new void LevelUp()
{
base.LevelUp();
// do specific things here... maybe increase range.
}
}
public class MeleeWeapon: BaseItem
{
public new void LevelUp()
{
base.LevelUp();
// do specific things here...
}
}
In an inventory manager, I have a list of all items, and can call the LevelUp method on them. The issue, I think, is that I have a list of <BaseItem>s and the specific classes LevelUp is not called:
public void LevelUpItem(string itemName)
{
var item = AvailableItems.First(w => w.ItemName.Equals(itemName));
item.LevelUp();
}
My original thought is that I need to upcast the item before calling the LevelUp function. My second thought is that I'm doing something way wrong here.
My specific question is "How do I upcast safely" and my unasked question is, "should I consider a different approach to polymorphism?"
In C# you can use virtual keyword (also there is abstract modifier in case you don't want to have any default implemenation) for polymorphism:
public abstract class BaseItem : MonoBehaviour
{
public virtual void LevelUp()
{
// do some common thing ... maybe increase damage
}
}
And use override modifier to change the behavior in inheritors:
public class RangedWeapon: BaseItem
{
public override void LevelUp()
{
base.LevelUp();
// do specific things here... maybe increase range.
}
}

How to implement class structure reasonable

I hope my question is legit because i'm not really used to all the hierarchical class structs.
I try to encapsulate a class that delivers the same functions for two different cameras connected to device. Those functions are thought to be within the class DeviceObject whilst I want to access those functions by using an instance of Camera1 or Camera2. Here's some pseudo code that might not work:
public class Camera1 : DeviceObject
{
public Generic.CameraSelect Camera { get; set; } = Generic.CameraSelect.CAM1;
}
public class Camera2 : DeviceObject
{
public Generic.CameraSelect Camera { get; set; } = Generic.CameraSelect.CAM2;
}
public class DeviceObject
{
public void SomeFunction()
{
HardwareDriver.Function(SelectedCamera);
}
}
What I want is to easly access the methods of DeviceObject dependend on the Camera-Class:
public void Method()
{
Camera1 Cam1 = New Camera1();
Camera2 Cam2 = New Camera2();
Cam1.SomeFunction();
Cam2.SomeFunction();
}
I apologize if this is a stupid question but after 7 hours of programming I'm completely stuck and don't get it in my head anymore :)
UPDATE:
I have implemented - as entirely all of you have recommended - an abstract base class and derivate the Camera Objects as member of the base class.
What I didn't know so far, that it's possible to cast derived classes to the type of base classes. That was absolutely new to me but helped me a looot! with my implementation.
So thanks to all of you who helped me without minusing me to hell :)
Why not use an abstract class?
public class Camera1 : Camera
{
public override Generic.CameraSelect CameraType { get; set; } = "CAM1";
}
public class Camera2 : Camera
{
public override Generic.CameraSelect CameraType { get; set; } = "CAM2";
}
public abstract class Camera
{
public abstract Generic.CameraSelect CameraType { get; set; }
public void SomeFunction()
{
HardwareDriver.Function(this);
}
}
You typically only use inheritance when you need different implementation (methods). If the implementation is the same for both cameras but the data involved is different, you can use one class and a factory to "create" a camera with the appropriate settings.
public class CameraFactory
{
public static Camera1 {
get {
return new Camera {Camera = Generic.CameraSelect.CAM1};
}
public static Camera2 {
get {
return new Camera {Camera = Generic.CameraSelect.CAM2};
}
}
That's not the only way to do it, but it is one way.
Also note that if the Camera property should not change then make it get-only (or at worst use a private setter.
As other people have suggested, the answer to your question is probably to add an abstract / override:
public class Camera1 : Camera
{
public override Generic.CameraSelect CameraType { get; set; } = "CAM1";
}
public class Camera2 : Camera
{
public override Generic.CameraSelect CameraType { get; set; } = "CAM2";
}
public abstract class Camera
{
public abstract Generic.CameraSelect CameraType { get; set; }
public void SomeFunction()
{
HardwareDriver.Function(this);
}
}
However, I was triggered by the HardwareDriver class. There are two points I'd like to make here:
Drivers work on capabilities, not on names. If you're goal is decomposition, you might want to go for a double dispatch that calls stuff depending on the scope.
What's the purpose of a camera and why is it modelled the way 'the world' works?
Double dispatch
Let's start with the double dispatch. The way I see it, you'll probably end up with a large 'switch' block somewhere that incorporates the logic. That doens't make a lot of sense to me. Basically you probably attempt to decouple the objects from the logic -- so let's use inheritance to do that. In this case, it'll work like this:
public class Camera1 : Camera
{
public override void SomeFunction(IDeviceVisitor driver)
{
// Very simple camera:
driver.HandleAngle(this, 12.0);
driver.GenerateModel();
}
}
public class Camera2 : Camera
{
public override void SomeFunction(IDeviceVisitor driver)
{
// This camera understands focus
driver.HandleAngle(this, 12.0);
driver.HandleFocus(this, focus, this.focus * 1.2);
driver.GenerateModel();
}
}
public class SomeHardwareDriver : IDeviceVisitor { ... }
public interface IDeviceVisitor
{
void HandleFocus(Camera camera, double focusValue, double realDistance);
void HandleAngle(Camera camera, double angle);
void GenerateModel();
// [...]
// etc
}
public abstract class Camera
{
public abstract void SomeFunction(IDeviceVisitor driver);
}
The reason I pass this along is because you might want to call another camera function from within the HardwareDriver to do the magic.
Modelling in the way the world works
If two camera have nothing with each other in common, don't give them a common base class. It makes no sense.
Or the more general rule: always remember that a class model doesn't need to make sense to you as a person; it has to make sense to a computer.
How to know when you're running the wrong way
2 clues:
If you end up with large switch blocks, a lot of if-then-else's, etc -- then you're probably doing it wrong.
If you copy-paste code, you're probably doing it wrong.
You can have a encapsulating method which accepts a parameter of DeviceObject like
public void CallSomeFunction(DeviceObject dobj)
{
dobj.SomeFunction();
}
Then you can create an instance of any of camera base type and call the method
Camera1 Cam1 = New Camera1();
CallSomeFunction(cam1);

Reference an object that instantiated another?

I have a class called Star, and it has a
public List<Planet> Planets = new List<Planet>();
There is a method that creates the Planets with the variables needed, though I want some of the information about the star accessible in the planet class.
right now there are 4 variables I construct the 'Planet Class' with but I need about 6 of the variables from the 'Star Class' available in the 'Planet Class'.
Is there a way to have a reference to the parent star in the planet class? and how would I pass the reference to the Planet?
Thanks!
You can include a reference in the Planet class to the Star. You can then create a constructor that takes that reference, like so:
public class Planet
{
private Star orbits;
...
public Planet(Star orbits)
{
this.orbits = orbits;
...
}
...
}
You can then instantiate it from in Star like this:
public List<Planet> Planets = new List<Planet>(this);
There are plenty of ways to accomplish this, just one idea:
What about making a parameter for your contstructor like:
private List<Star> _solarSystem;
Planet(List<Star> solarSystem)
{
this._solarSystem = solarSystem;
}
From OO point of view it would be better to have instead of the list a class. I assume the code you have posted is also in some class, so how is your class called ?
private SolarSystem _solarSystem;
Planet(SolarSystem solarSystem)
{
this._solarSystem = solarSystem;
}
A typical solution is to inject an interface that the class implements into the dependent class (dependency injection). Something like this for your case:
internal interface IStar
{
void Method1();
string Property1 { get; }
...
}
internal abstract class Star : IStar
{
protected Star()
{
foreach(string planetName in planetNames)
{
Planet p = new Planet(planetName, this);
Planets.Add(p);
}
}
public void Method1()
{
...
}
public string Property1
{
get { return string.Empty; }
}
}
internal class Planet
{
string name;
IStar parentStar;
internal Planet(string name, IStar parentStar)
{
this.name = name;
this.parentStar = parentStar;
}
}
Doing it in this fashion allows you to pass in different classes that implement IStar if needed. Maybe you have the base abstract class Star, which is inherited by ClassAStar, DwarfStar, etc. The Planet doesn't care what kind of star you pass in, as long as it implements the IStar interface. This promotes loose coupling, making your code easier to maintain.
Use dictionary like this:
IDictionary<Star, IList<Planet>> planetSystems = new Dictionary<Star, IList<Planet>>();

Interface with implementation without abstract class?

I am writing a library and I want to have an interface
public interface ISkeleton
{
IEnumerable<IBone> Bones { get; }
void Attach(IBone bone);
void Detach(IBone bone);
}
The Attach() and Detach() implementation actually should be the same for every ISkeleton. Thus, it could essentially be:
public abstract class Skeleton
{
public IEnumerable<IBone> Bones { get { return _mBones; } }
public List<IBone> _mBones = new List<IBone>();
public void Attach(IBone bone)
{
bone.Transformation.ToLocal(this);
_mBones.add();
}
public void Detach(IBone bone)
{
bone.Transformation.ToWorld(this);
_mBones.Remove(bone);
}
}
But C# doesn't allow multiple inheritance. So among various issues, users have to remember to inherit from Skeleton every time they want to implement Skeleton.
I could use extension methods
public static class Skeleton
{
public static void Attach(this ISkeleton skeleton, IBone bone)
{
bone.Transformation.ToLocal(skeleton);
skeleton.Bones.add(bone);
}
public static void Detach(this ISkeleton skeleton, IBone bone)
{
bone.Transformation.ToWorld(this);
skeleton.Bones.Remove(bone);
}
}
But then I need to have
public interface ISkeleton
{
ICollection<IBone> Bones { get; }
}
Which I do not want, because it is not covariant and users can bypass the Attach() and Detach() methods.
Question: Must I really use an abstract Skeleton class or are there any or tricks and methods?
If you need to expose the Attach and Detach methods in your interface, there is always a way to bypass your intended implementations, as all objects implementing the interface can implement them on their own style.
You can let the abstract class Skeleton implement ISkeleton and all classes which are Skeletons do inherit from Skeleton, thus they implement ISkeleton as well.
public interface ISkeleton { ... }
public abstract class Skeleton : ISkeleton { ... } // implement attach and detach
public class SampleSkeleton : Skeleton { ... }
This way you can use your SampleSkeleton as ISkeleton, you don't have to implement these functions as long as you inherit from Skeleton and marking the methods as sealed does not allow overriding them (as long as they are instance methods).
On a side node: Do name your abstract class with Base at the end or mark the base class somehow else (but this is surely up to you).
I would make bones a special type that implements IEnumerable<T>. That way it doesn't violate the single responsibility principle.
public interface ISkeleton
{
AttachableEnumerable<IBone> Bones { get; }
}
public class AttachableEnumerable<T> : IEnumerable<T>
{
// implementation needed.
void Attach(T item);
void Detach(T item);
}
If you want to wrap ISkeleton behaviour, you could always make it a composite object instead of inheriting the behaviour:
public class Body : ISkeleton
{
private SkeletonImpl _skeleton = new SkeletonImpl;
public IEnumerable<IBone> Bones { get { return _skeleton.Bones; } }
public void Attach(IBone bone)
{
_skeleton.Attach(bone);
}
public void Detach(IBone bone)
{
_skeleton.Detach(bone);
}
}
May be you just have to use sealed methods on abstract Skeleton class?
This way they can't be overriden.
http://msdn.microsoft.com/en-us/library/aa645769(v=vs.71).aspx
You can create a wrapper class which implements the 'Attach' and 'Detach' methods and inject this Functionality to your Interface.

Interface defining a constructor signature?

It's weird that this is the first time I've bumped into this problem, but:
How do you define a constructor in a C# interface?
Edit
Some people wanted an example (it's a free time project, so yes, it's a game)
IDrawable
+Update
+Draw
To be able to Update (check for edge of screen etc) and draw itself it will always need a GraphicsDeviceManager. So I want to make sure the object has a reference to it. This would belong in the constructor.
Now that I wrote this down I think what I'm implementing here is IObservable and the GraphicsDeviceManager should take the IDrawable...
It seems either I don't get the XNA framework, or the framework is not thought out very well.
Edit
There seems to be some confusion about my definition of constructor in the context of an interface. An interface can indeed not be instantiated so doesn't need a constructor. What I wanted to define was a signature to a constructor. Exactly like an interface can define a signature of a certain method, the interface could define the signature of a constructor.
You can't. It's occasionally a pain, but you wouldn't be able to call it using normal techniques anyway.
In a blog post I've suggested static interfaces which would only be usable in generic type constraints - but could be really handy, IMO.
One point about if you could define a constructor within an interface, you'd have trouble deriving classes:
public class Foo : IParameterlessConstructor
{
public Foo() // As per the interface
{
}
}
public class Bar : Foo
{
// Yikes! We now don't have a parameterless constructor...
public Bar(int x)
{
}
}
As already well noted, you can't have constructors on an Interface. But since this is such a highly ranked result in Google some 7 years later, I thought I would chip in here - specifically to show how you could use an abstract base class in tandem with your existing Interface and maybe cut down on the amount of refactoring needed in the future for similar situations. This concept has already been hinted at in some of the comments but I thought it would be worth showing how to actually do it.
So you have your main interface that looks like this so far:
public interface IDrawable
{
void Update();
void Draw();
}
Now create an abstract class with the constructor you want to enforce. Actually, since it's now available since the time you wrote your original question, we can get a little fancy here and use generics in this situation so that we can adapt this to other interfaces that might need the same functionality but have different constructor requirements:
public abstract class MustInitialize<T>
{
public MustInitialize(T parameters)
{
}
}
Now you'll need to create a new class that inherits from both the IDrawable interface and the MustInitialize abstract class:
public class Drawable : MustInitialize<GraphicsDeviceManager>, IDrawable
{
GraphicsDeviceManager _graphicsDeviceManager;
public Drawable(GraphicsDeviceManager graphicsDeviceManager)
: base (graphicsDeviceManager)
{
_graphicsDeviceManager = graphicsDeviceManager;
}
public void Update()
{
//use _graphicsDeviceManager here to do whatever
}
public void Draw()
{
//use _graphicsDeviceManager here to do whatever
}
}
Then just create an instance of Drawable and you're good to go:
IDrawable drawableService = new Drawable(myGraphicsDeviceManager);
The cool thing here is that the new Drawable class we created still behaves just like what we would expect from an IDrawable.
If you need to pass more than one parameter to the MustInitialize constructor, you can create a class that defines properties for all of the fields you'll need to pass in.
A very late contribution demonstrating another problem with interfaced constructors. (I choose this question because it has the clearest articulation of the problem). Suppose we could have:
interface IPerson
{
IPerson(string name);
}
interface ICustomer
{
ICustomer(DateTime registrationDate);
}
class Person : IPerson, ICustomer
{
Person(string name) { }
Person(DateTime registrationDate) { }
}
Where by convention the implementation of the "interface constructor" is replaced by the type name.
Now make an instance:
ICustomer a = new Person("Ernie");
Would we say that the contract ICustomer is obeyed?
And what about this:
interface ICustomer
{
ICustomer(string address);
}
You can't.
Interfaces define contracts that other objects implement and therefore have no state that needs to be initialized.
If you have some state that needs to be initialized, you should consider using an abstract base class instead.
I was looking back at this question and I thought to myself, maybe we are aproaching this problem the wrong way. Interfaces might not be the way to go when it concerns defining a constructor with certain parameters... but an (abstract) base class is.
If you create a base class with a constructor on there that accepts the parameters you need, every class that derrives from it needs to supply them.
public abstract class Foo
{
protected Foo(SomeParameter x)
{
this.X = x;
}
public SomeParameter X { get; private set }
}
public class Bar : Foo // Bar inherits from Foo
{
public Bar()
: base(new SomeParameter("etc...")) // Bar will need to supply the constructor param
{
}
}
It is not possible to create an interface that defines constructors, but it is possible to define an interface that forces a type to have a paramerterless constructor, though be it a very ugly syntax that uses generics... I am actually not so sure that it is really a good coding pattern.
public interface IFoo<T> where T : new()
{
void SomeMethod();
}
public class Foo : IFoo<Foo>
{
// This will not compile
public Foo(int x)
{
}
#region ITest<Test> Members
public void SomeMethod()
{
throw new NotImplementedException();
}
#endregion
}
On the other hand, if you want to test if a type has a paramerterless constructor, you can do that using reflection:
public static class TypeHelper
{
public static bool HasParameterlessConstructor(Object o)
{
return HasParameterlessConstructor(o.GetType());
}
public static bool HasParameterlessConstructor(Type t)
{
// Usage: HasParameterlessConstructor(typeof(SomeType))
return t.GetConstructor(new Type[0]) != null;
}
}
Hope this helps.
One way to solve this problem i found is to seperate out the construction into a seperate factory. For example I have an abstract class called IQueueItem, and I need a way to translate that object to and from another object (CloudQueueMessage). So on the interface IQueueItem i have -
public interface IQueueItem
{
CloudQueueMessage ToMessage();
}
Now, I also need a way for my actual queue class to translate a CloudQueueMessage back to a IQueueItem - ie the need for a static construction like IQueueItem objMessage = ItemType.FromMessage. Instead I defined another interface IQueueFactory -
public interface IQueueItemFactory<T> where T : IQueueItem
{
T FromMessage(CloudQueueMessage objMessage);
}
Now I can finally write my generic queue class without the new() constraint which in my case was the main issue.
public class AzureQueue<T> where T : IQueueItem
{
private IQueueItemFactory<T> _objFactory;
public AzureQueue(IQueueItemFactory<T> objItemFactory)
{
_objFactory = objItemFactory;
}
public T GetNextItem(TimeSpan tsLease)
{
CloudQueueMessage objQueueMessage = _objQueue.GetMessage(tsLease);
T objItem = _objFactory.FromMessage(objQueueMessage);
return objItem;
}
}
now I can create an instance that satisfies the criteria for me
AzureQueue<Job> objJobQueue = new JobQueue(new JobItemFactory())
hopefully this helps someone else out someday, obviously a lot of internal code removed to try to show the problem and solution
One way to solve this problem is to leverage generics and the new() constraint.
Instead of expressing your constructor as a method/function, you can express it as a factory class/interface. If you specify the new() generic constraint on every call site that needs to create an object of your class, you will be able to pass constructor arguments accordingly.
For your IDrawable example:
public interface IDrawable
{
void Update();
void Draw();
}
public interface IDrawableConstructor<T> where T : IDrawable
{
T Construct(GraphicsDeviceManager manager);
}
public class Triangle : IDrawable
{
public GraphicsDeviceManager Manager { get; set; }
public void Draw() { ... }
public void Update() { ... }
public Triangle(GraphicsDeviceManager manager)
{
Manager = manager;
}
}
public TriangleConstructor : IDrawableConstructor<Triangle>
{
public Triangle Construct(GraphicsDeviceManager manager)
{
return new Triangle(manager);
}
}
Now when you use it:
public void SomeMethod<TBuilder>(GraphicsDeviceManager manager)
where TBuilder: IDrawableConstructor<Triangle>, new()
{
// If we need to create a triangle
Triangle triangle = new TBuilder().Construct(manager);
// Do whatever with triangle
}
You can even concentrate all creation methods in a single class using explicit interface implementation:
public DrawableConstructor : IDrawableConstructor<Triangle>,
IDrawableConstructor<Square>,
IDrawableConstructor<Circle>
{
Triangle IDrawableConstructor<Triangle>.Construct(GraphicsDeviceManager manager)
{
return new Triangle(manager);
}
Square IDrawableConstructor<Square>.Construct(GraphicsDeviceManager manager)
{
return new Square(manager);
}
Circle IDrawableConstructor<Circle>.Construct(GraphicsDeviceManager manager)
{
return new Circle(manager);
}
}
To use it:
public void SomeMethod<TBuilder, TShape>(GraphicsDeviceManager manager)
where TBuilder: IDrawableConstructor<TShape>, new()
{
// If we need to create an arbitrary shape
TShape shape = new TBuilder().Construct(manager);
// Do whatever with the shape
}
Another way is by using lambda expressions as initializers. At some point early in the call hierarchy, you will know which objects you will need to instantiate (i.e. when you are creating or getting a reference to your GraphicsDeviceManager object). As soon as you have it, pass the lambda
() => new Triangle(manager)
to subsequent methods so they will know how to create a Triangle from then on. If you can't determine all possible methods that you will need, you can always create a dictionary of types that implement IDrawable using reflection and register the lambda expression shown above in a dictionary that you can either store in a shared location or pass along to further function calls.
The generic factory approach still seems ideal. You would know that the factory requires a parameter, and it would just so happen that those parameters are passed along to the constructor of the object being instantiated.
Note, this is just syntax verified pseudo code, there may be a run-time caveat I'm missing here:
public interface IDrawableFactory
{
TDrawable GetDrawingObject<TDrawable>(GraphicsDeviceManager graphicsDeviceManager)
where TDrawable: class, IDrawable, new();
}
public class DrawableFactory : IDrawableFactory
{
public TDrawable GetDrawingObject<TDrawable>(GraphicsDeviceManager graphicsDeviceManager)
where TDrawable : class, IDrawable, new()
{
return (TDrawable) Activator
.CreateInstance(typeof(TDrawable),
graphicsDeviceManager);
}
}
public class Draw : IDrawable
{
//stub
}
public class Update : IDrawable {
private readonly GraphicsDeviceManager _graphicsDeviceManager;
public Update() { throw new NotImplementedException(); }
public Update(GraphicsDeviceManager graphicsDeviceManager)
{
_graphicsDeviceManager = graphicsDeviceManager;
}
}
public interface IDrawable
{
//stub
}
public class GraphicsDeviceManager
{
//stub
}
An example of possible usage:
public void DoSomething()
{
var myUpdateObject = GetDrawingObject<Update>(new GraphicsDeviceManager());
var myDrawObject = GetDrawingObject<Draw>(null);
}
Granted, you'd only want the create instances via the factory to guarantee you always have an appropriately initialized object. Perhaps using a dependency injection framework like AutoFac would make sense; Update() could "ask" the IoC container for a new GraphicsDeviceManager object.
You could do this with generics trick, but it still is vulnerable to what Jon Skeet wrote:
public interface IHasDefaultConstructor<T> where T : IHasDefaultConstructor<T>, new()
{
}
Class that implements this interface must have parameterless constructor:
public class A : IHasDefaultConstructor<A> //Notice A as generic parameter
{
public A(int a) { } //compile time error
}
The purpose of an interface is to enforce a certain object signature. It should explicitly not be concerned with how an object works internally. Therefore, a constructor in an interface does not really make sense from a conceptual point of view.
There are some alternatives though:
Create an abstract class that acts as a minimal default implementation.
That class should have the constructors you expect implementing classes
to have.
If you don't mind the overkill, use the AbstractFactory pattern and
declare a method in the factory class interface that has the required
signatures.
Pass the GraphicsDeviceManager as a parameter to the Update and Draw methods.
Use a Compositional Object Oriented Programming framework to pass the GraphicsDeviceManager into the part of the object that requires it. This is a pretty experimental solution in my opinion.
The situation you describe is not easy to handle in general. A similar case would be entities in a business application that require access to the database.
you don't.
the constructor is part of the class that can implement an interface. The interface is just a contract of methods the class must implement.
It would be very useful if it were possible to define constructors in interfaces.
Given that an interface is a contract that must be used in the specified way. The following approach might be a viable alternative for some scenarios:
public interface IFoo {
/// <summary>
/// Initialize foo.
/// </summary>
/// <remarks>
/// Classes that implement this interface must invoke this method from
/// each of their constructors.
/// </remarks>
/// <exception cref="InvalidOperationException">
/// Thrown when instance has already been initialized.
/// </exception>
void Initialize(int a);
}
public class ConcreteFoo : IFoo {
private bool _init = false;
public int b;
// Obviously in this case a default value could be used for the
// constructor argument; using overloads for purpose of example
public ConcreteFoo() {
Initialize(42);
}
public ConcreteFoo(int a) {
Initialize(a);
}
public void Initialize(int a) {
if (_init)
throw new InvalidOperationException();
_init = true;
b = a;
}
}
One way to force some sort of constructor is to declare only Getters in interface, which could then mean that the implementing class must have a method, ideally a constructor, to have the value set (privately) for it.
While you can't define a constructor signature in an interface, I feel it's worth mentioning that this may be a spot to consider an abstract class. Abstract classes can define unimplemented (abstract) method signatures in the same way as an interface, but can also have implemented (concrete) methods and constructors.
The downside is that, because it is a type of class, it cannot be used for any of the multiple inheritance type scenarios that an interface can.
I use the following pattern to make it bulletproof.
A developer who derives his class from the base can't accidentally create a public accessible constructor
The final class developer are forced to go through the common create method
Everything is type-safe, no castings are required
It's 100% flexible and can be reused everywhere, where you can define your own base
class.
Try it out you can't break it without making modifications to the base classes (except
if you define an obsolete flag without error flag set to true, but even then you end up with a warning)
public abstract class Base<TSelf, TParameter>
where TSelf : Base<TSelf, TParameter>, new()
{
protected const string FactoryMessage = "Use YourClass.Create(...) instead";
public static TSelf Create(TParameter parameter)
{
var me = new TSelf();
me.Initialize(parameter);
return me;
}
[Obsolete(FactoryMessage, true)]
protected Base()
{
}
protected virtual void Initialize(TParameter parameter)
{
}
}
public abstract class BaseWithConfig<TSelf, TConfig>: Base<TSelf, TConfig>
where TSelf : BaseWithConfig<TSelf, TConfig>, new()
{
public TConfig Config { get; private set; }
[Obsolete(FactoryMessage, true)]
protected BaseWithConfig()
{
}
protected override void Initialize(TConfig parameter)
{
this.Config = parameter;
}
}
public class MyService : BaseWithConfig<MyService, (string UserName, string Password)>
{
[Obsolete(FactoryMessage, true)]
public MyService()
{
}
}
public class Person : Base<Person, (string FirstName, string LastName)>
{
[Obsolete(FactoryMessage,true)]
public Person()
{
}
protected override void Initialize((string FirstName, string LastName) parameter)
{
this.FirstName = parameter.FirstName;
this.LastName = parameter.LastName;
}
public string LastName { get; private set; }
public string FirstName { get; private set; }
}
[Test]
public void FactoryTest()
{
var notInitilaizedPerson = new Person(); // doesn't compile because of the obsolete attribute.
Person max = Person.Create(("Max", "Mustermann"));
Assert.AreEqual("Max",max.FirstName);
var service = MyService.Create(("MyUser", "MyPassword"));
Assert.AreEqual("MyUser", service.Config.UserName);
}
EDIT:
And here is an example based on your drawing example that even enforces interface abstraction
public abstract class BaseWithAbstraction<TSelf, TInterface, TParameter>
where TSelf : BaseWithAbstraction<TSelf, TInterface, TParameter>, TInterface, new()
{
[Obsolete(FactoryMessage, true)]
protected BaseWithAbstraction()
{
}
protected const string FactoryMessage = "Use YourClass.Create(...) instead";
public static TInterface Create(TParameter parameter)
{
var me = new TSelf();
me.Initialize(parameter);
return me;
}
protected virtual void Initialize(TParameter parameter)
{
}
}
public abstract class BaseWithParameter<TSelf, TInterface, TParameter> : BaseWithAbstraction<TSelf, TInterface, TParameter>
where TSelf : BaseWithParameter<TSelf, TInterface, TParameter>, TInterface, new()
{
protected TParameter Parameter { get; private set; }
[Obsolete(FactoryMessage, true)]
protected BaseWithParameter()
{
}
protected sealed override void Initialize(TParameter parameter)
{
this.Parameter = parameter;
this.OnAfterInitialize(parameter);
}
protected virtual void OnAfterInitialize(TParameter parameter)
{
}
}
public class GraphicsDeviceManager
{
}
public interface IDrawable
{
void Update();
void Draw();
}
internal abstract class Drawable<TSelf> : BaseWithParameter<TSelf, IDrawable, GraphicsDeviceManager>, IDrawable
where TSelf : Drawable<TSelf>, IDrawable, new()
{
[Obsolete(FactoryMessage, true)]
protected Drawable()
{
}
public abstract void Update();
public abstract void Draw();
}
internal class Rectangle : Drawable<Rectangle>
{
[Obsolete(FactoryMessage, true)]
public Rectangle()
{
}
public override void Update()
{
GraphicsDeviceManager manager = this.Parameter;
// TODo manager
}
public override void Draw()
{
GraphicsDeviceManager manager = this.Parameter;
// TODo manager
}
}
internal class Circle : Drawable<Circle>
{
[Obsolete(FactoryMessage, true)]
public Circle()
{
}
public override void Update()
{
GraphicsDeviceManager manager = this.Parameter;
// TODo manager
}
public override void Draw()
{
GraphicsDeviceManager manager = this.Parameter;
// TODo manager
}
}
[Test]
public void FactoryTest()
{
// doesn't compile because interface abstraction is enforced.
Rectangle rectangle = Rectangle.Create(new GraphicsDeviceManager());
// you get only the IDrawable returned.
IDrawable service = Circle.Create(new GraphicsDeviceManager());
}

Categories