I'm a new developer of c# and I'm using unity3d to develop a game.
I design an interface to implement the skill system in game. But I find some trouble. Here are a lot of Skill classes, and I must call show() method manually inside their apply.
interface ISkill
{
void apply();
}
class Base
{
protected string name { get; set; }
protected void show()
{
Console.WriteLine("show:"+name);
}
}
class Skill1 : Base, ISkill
{
public Skill1()
{
name = "skill1";
}
public void apply()
{
show();
Console.WriteLine("skill1 apply");
}
}
class Skill2 : Base, ISkill
{
public Skill2()
{
name = "skill2";
}
public void apply()
{
show();
Console.WriteLine("skill2 apply");
}
}
Skill3
Skill4
etc..
class Program
{
public static void Main(string[] args)
{
ISkill skill = new Skill2();
skill.apply();
}
}
How to modify my code so that the all SkillX classes can automatically call show() method in apply() method?
Standard solution for this is template method.
Base class implements method as "template" that forces derived classes to provide particular step(s) for that method. In your case the Base class should implement Apply method that calls Show first and than delegates the rest to derived classes by forcing them to provide implementation of the second part via abstract void ApplyImplementation():
interface ISkill
{
void Apply();
}
public abstract class Base
{
protected string name { get; set; }
protected Base(string name)
{
this.name = name;
}
protected void Show()
{
Console.WriteLine("show:"+name);
}
// "template" method.
public void Apply()
{
Show();
ApplyImplementation();
}
// derived class must implement that method
protected abstract void ApplyImplementation();
}
class Skill1 : Base, ISkill
{
public Skill1()
{
name = "skill1";
}
protected override void ApplyImplementation()
{
Console.WriteLine("skill1 apply");
}
}
No general solution, other than trying to pull the commonality across different classes to the base.
In your case, since the only differences among the apply() seems to be the skill name, and you already have it as an instance property, you can pull the apply up to the Base, and have the same implementation across all the child classes of Base.
interface ISkill
{
void apply();
}
class Base : ISkill
{
protected string name { get; set; }
protected Base(string name)
{
this.name = name;
}
public void apply()
{
show();
Console.WriteLine(name + " apply");
}
private void show()
{
Console.WriteLine("show:"+name);
}
}
class Skill1 : Base
{
public Skill1(): base("skill1"){}
}
class Skill2 : Base
{
public Skill2(): base("skill2"){}
}
Related
I have an "inheritance-tree" which looks like this:
There is common code for the "TargetWithTeststand" and i would like to have a common code source. My only idea would be to use a separate static class and gather the methods which are common.
Another idea was to use a common interface with default methods, but this does not support override.
Do you have any better idea how to deal with such inheritance problems?
Here is a code example:
using System;
public class Program
{
public static void Main()
{
int deviceType = 1; // This value is read from a config file which can be changed
Device device = null;
switch (deviceType)
{
case 0:
device = new TargetWithTeststandDev1();
break;
case 1:
device = new TargetWithSimulationDev2();
break;
// [....]
}
device.ReadMotorSpeed();
device.UsePowerButton();
}
}
public abstract class Device
{
public virtual void UsePowerButton()
{
throw new NotImplementedException();
}
public virtual void ReadMotorSpeed()
{
throw new NotImplementedException();
}
}
public abstract class DeviceType1 : Device
{
public override void ReadMotorSpeed()
{
Console.WriteLine("Read motor speed with DeviceType1");
}
}
public abstract class DeviceType2 : Device
{
public override void ReadMotorSpeed()
{
Console.WriteLine("Read motor speed with DeviceType2");
}
}
public sealed class TargetWithTeststandDev1 : DeviceType1
{
public override void UsePowerButton()
{
Console.WriteLine("UsePowerButton on teststand with DeviceType1");
}
}
public sealed class TargetWithSimulationDev1 : DeviceType1
{
public override void UsePowerButton()
{
Console.WriteLine("UsePowerButton on teststand with DeviceType1");
}
}
public sealed class TargetWithTargetDev1 : DeviceType1
{
public override void UsePowerButton()
{
Console.WriteLine("UsePowerButton on Target with DeviceType1");
}
}
public sealed class TargetWithTeststandDev2 : DeviceType2
{
public override void UsePowerButton()
{
Console.WriteLine("UsePowerButton on Simulation with DeviceType2");
}
}
public sealed class TargetWithSimulationDev2 : DeviceType2
{
public override void UsePowerButton()
{
Console.WriteLine("UsePowerButton on Simulation with DeviceType2");
}
}
public sealed class TargetWithTargetDev2 : DeviceType2
{
public override void UsePowerButton()
{
Console.WriteLine("UsePowerButton on Target with DeviceType2");
}
}
You have literally drawn the diamond problem, One of the main reasons multiple inheritance is not supported.
The typical solution to this is to use composition instead of inheritance. I.e. gather all the common functions for a simulation in a separate class, that your SimulationDev1 and SimulationDev2 classes refer to, and any simulation operations would be delegated to this class.
An alternative would be to use interfaces and extension methods or default interface implementations to do more or less the same thing:
public interface ISimulation
{
int AProperty { get; }
}
public static class SimulationExtensions
{
public static int SomeCommonMethod(this ISimulation self, int b) => self.AProperty + b;
}
Given the following classes structure, is there a way to prevent BaseMethod() from being called or seen from FinalClass?
public abstract class BaseClass
{
protected virtual void BaseMethod()
{
}
}
public class IntermediateClass : BaseClass
{
protected sealed override void BaseMethod()
{
base.BaseMethod();
}
private void IntermediateMethod()
{
BaseMethod();
}
}
public class FinalClass : IntermediateClass
{
protected void FinalMethod()
{
}
}
You could make BaseMethod internal and place FinalClass in a different assembly to BaseClass and IntermediateClass.
I have a abstract base class, starting a timer which is common to all derived class,
public abstract class BaseClass
{
public virtual void Start() { _timer.Start(); }
}
Now I need to load different JSON configuration files for each derived class and create the file,
public class DerivedClass1 : BaseClass
{
private readonly List<config> configs = new List<config>();
public DerivedClass1()
{
configs = JsonSettings.GetConfigurations(#"./Configurations/1.json");
}
public override void Start()
{
base.Start();
foreach (var configuration in configs)
{
JsonSettings.CreateConfigFile(configuration);
}
}
}
public class DerivedClass2 : BaseClass
{
private readonly List<config> configs = new List<config>();
public DerivedClass2()
{
configs = JsonSettings.GetConfigurations(#"./Configurations/2.json");
}
public override void Start()
{
base.Start();
foreach (var configuration in configs)
{
JsonSettings.CreateConfigFile(configuration);
}
}
}
As I see there are lots of codes are duplicated in various derived class.
Can I move these piece of code as well as abstract base class or is there another way?
I think you could simplify your code to this:
public abstract class BaseClass
{
protected virtual List<config> configs { get; set; } = new List<config>();
public virtual void Start()
{
_timer.Start();
foreach (var configuration in configs)
{
JsonSettings.CreateConfigFile(configuration);
}
}
}
public class DerivedClass1 : BaseClass
{
public DerivedClass1()
{
configs = JsonSettings.GetConfigurations(#"./Configurations/1.json");
}
}
public class DerivedClass2 : BaseClass
{
public DerivedClass2()
{
configs = JsonSettings.GetConfigurations(#"./Configurations/2.json");
}
}
public interface BaseClass
{
void Start();
}
public interface IBaseClassUtil
{
void Start();
void setConfigs(List<config> configs);
}
public class BaseClassUtil : IBaseClassUtil
{
System.Timers.Timer _timer;
public List<config> _configs { get; set; } = new List<config>();
public void Start()
{
_timer.Start();
foreach (var configuration in _configs)
{
JsonSettings.CreateConfigFile(configuration);
}
}
public void setConfigs(List<config> configs)
{
_configs = configs;
}
}
public class DerivedClass1 : BaseClass
{
private IBaseClassUtil _baseUtility;
public DerivedClass1(IBaseClassUtil baseUtility)
{
_baseUtility = baseUtility;
_baseUtility.setConfigs( JsonSettings.GetConfigurations(#"./Configurations/1.json"));
}
public void Start()
{
_baseUtility.Start();
}
}
public class DerivedClass2 : BaseClass
{
private IBaseClassUtil _baseUtility;
public DerivedClass2(IBaseClassUtil baseUtility)
{
_baseUtility = baseUtility;
_baseUtility.setConfigs(JsonSettings.GetConfigurations(#"./Configurations/2.json"));
}
public void Start()
{
_baseUtility.Start();
}
}
This might be oveer engineered. Or might not suit ur current requirement.
Advantages would be
In future if you want u want to have different implementation for IBaseClassUtil it will be easier
And huge advantage would be this code is testable
If the classes differ by nothing but the configuration path, then you can have only one derived class that takes the path as a parameter in its ctor.
public DerivedClass(string configurationPath)
{
configs = JsonSettings.GetConfigurations(configurationPath);
}
Put please note that a decision on including inheritance in your architecture is not about code duplication, and by not giving us any information on the functions or even names of the classes (BaseClass and DerivedClass mean nothing. What do they represent? What's their function? Why are they related?) you give us no way of really helping you with your design.
I am attempting to override/overload a virtual function that has already been overridden in a base class. To better understand what I want to do please look at the following example:
public class Parent
{
public virtual void foo() {
print("Parent::foo()");
}
}
public class Derived : Parent
{
public override void foo() {
print("Derived::foo()");
}
}
public class Child : Derived
{
public override void foo() {
print("Child::foo()");
}
}
// When I create an instance of Child and call the method foo,
// it calls the Derived::foo() method and not Child::foo()
// How can I make Child override Derived::foo()?
Is it possible to override Derived::foo()? If not how would you suggest I solve this problem?
This calls Child::foo in C#. Try this code:
class Program {
static void Main()
{
Parent foo = new Child();
foo.foo();
}
}
// Define other methods and classes here
public class Parent
{
public virtual void foo() {
Console.WriteLine("Parent::foo()");
}
}
public class Derived : Parent
{
public override void foo() {
Console.WriteLine("Derived::foo()");
}
}
public class Child : Derived
{
public override void foo() {
Console.WriteLine("Child::foo()");
}
}
This will run and print Child::foo().
I can't say for sure without seeing your calling code, but are you sure you didn't make a mistake and create an instance of Derived?
I want to create a class that can only be inherited, for that i know it should be made abstract. But now the problem is that i want to use functions of that class without making them static. How can i do that.
public abstract Class A
{
A()
{}
public void display()
{}
}
public Class B:A
{
base.A() // this is accessible
this.display() // this is not accessible if i dont make this function static above
}
Your example will not compile, you could consider something like this:
using System;
public abstract class A
{
protected A()
{
Console.WriteLine("Constructor A() called");
}
public void Display()
{
Console.WriteLine("A.Display() called");
}
}
public class B:A
{
public void UseDisplay()
{
Display();
}
}
public class Program
{
static void Main()
{
B b = new B();
b.UseDisplay();
Console.ReadLine();
}
}
Output:
Constructor A() called
A.Display() called
Note: Creating a new B() implicitly calls A(); I had to make the constructor of A protected to prevent this error:
"'A.A()' is inaccessible due to its protection level"
That's not true. You don't have to make Display() static; you can call it freely from the subclass. On the other hand, you can't call the constructor like that.
Maybe it's just an error in the example, but the real issue with the code you have is that you can't put method calls in the middle of your class definition.
Try this:
public abstract class A
{
public void Display(){}
}
public class B:A
{
public void SomethingThatCallsDisplay()
{
Display();
}
}
Here's how you can do this..
public abstract class A
{
public virtual void display() { }
}
public class B : A
{
public override void display()
{
base.display();
}
public void someothermethod()
{
this.display();
}
}