Как написать 2 класса с одинаковым методом и наследования? - PullRequest
2 голосов
/ 08 октября 2019

У меня есть X классов с различной информацией и методами расчета, которые должны быть разделены, но могут быть перезаписаны, поэтому:

class Rule1 {
    int type = 1;
    string name = "Rule";
    public float Calc()
    {
        return 1 + 2 + type; // SAME
    }
}

class Rule2 {
    int type = 2;
    string name = "Rule2";
    public float Calc()
    {
        return 1 + 2 + type; // SAME
    }
}

class Rule3 {
    int type = 3;
    string name = "Rule3";
    public float Calc()
    {
        return 3 + 4 + type; // DIFFERENT
    }
}

То, что я хочу записать в вызывающих методах, выглядит следующим образом:

class Calculator
{
    public void Do(List<IRules> ruleList)
    {
        foreach(var rule in ruleList)
        {
            rule.Calc();
        }
    }
}

Так как должен выглядеть мой интерфейс и как абстрагировать метод calc как реализацию по умолчанию, но перезаписать?

Ответы [ 4 ]

5 голосов
/ 08 октября 2019

Если у вас есть реализация, которая подходит для большинства наследников, но не для всех, отметьте ее virtual и override в производном классе:

public class BaseCalculation
{
    public virtual float Calculate()
    {
        return 42;
    }
}

public class HalfCalculation : BaseCalculation
{
    public override float Calculate()
    {
        return 21;
    }
}

Теперь вы можете использовать базовый класс, BaseCalculation вместо интерфейса. Если вы по-прежнему настаиваете на использовании интерфейса, вы все равно можете определить метод Calculate() в интерфейсе и применить его к своему базовому классу:

public interface IRules
{
    float Calculate();
}

public class BaseCalculation : IRules
{
    // same as above

С дополнительным преимуществом, вы можете применить этот интерфейс к другие классы, которые тоже что-то вычисляют, но без какой-либо логики, которая есть в BaseCalculation.

2 голосов
/ 08 октября 2019

Вы можете попробовать это, используя базовый класс asbtract и полиморфизм на Calc.

Что такое полиморфизм

Нет необходимости использовать интерфейс, если у вас нет реальногои веская причина для этого.

В чем разница между интерфейсом и классом

Мы используем защищенный конструктор для распространения параметров.

class Calculator
{
  public void Do(List<RuleBase> ruleList)
  {
    foreach ( var rule in ruleList )
    {
      // do what you want with the result of rule.Calc();
    }
  }
}
public abstract class RuleBase
{
  public int Type { get; private set; }
  public string Name { get; private set; }
  public abstract float Calc();
  protected RuleBase(int type, string name)
  {
    Type = type;
    Name = name;
  }
}
public class Rule1 : RuleBase
{
  public override float Calc()
  {
    return 1 + 2 + Type;
  }
  public Rule1()
    : base(1, "Rule1")
  {
  }
  protected Rule1(int type, string name)
    : base(type, name)
  {
  }
}
public class Rule2 : Rule1
{
  public Rule2()
    : base(2, "Rule2")
  {
  }
  protected Rule2(int type, string name)
    : base(type, name)
  {
  }
}
public class Rule3 : RuleBase
{
  public override float Calc()
  {
    return 3 + 4 + Type;
  }
  public Rule3()
    : base(3, "Rule3")
  {
  }
  protected Rule3(int type, string name)
    : base(type, name)
  {
  }
}

Если вы хотите создать интерфейс и добавить его в RuleBase:

public interface IRule
{
  float Calc();
}

public abstract class RuleBase : IRule
1 голос
/ 08 октября 2019

Вы ищете унаследованный класс и виртуальный метод (который позволяет переопределить):

class GenericRule {
    int type = 1;
    string name = "Rule";
    public virtual float Calc()
    {
        return 1 + 2 + type; // SAME
    }
}

class Rule3 : GenericRule
{
    int type = 3;
    string name = "Rule3";
    public override float Calc()
    {
        return 3 + 4 + type; // DIFFERENT
    }
}

class Calculator
{
    public void Do(List<GenericRule> ruleList)
    {
        foreach(var rule in ruleList)
        {
            rule.Calc();
        }
    }
}
0 голосов
/ 08 октября 2019

Каждый класс должен поддерживать интерфейс. Реализация метода Calc в каждом классе не важна. Они могут быть одинаковыми или разными.

Если вы хотите иметь стандартную реализацию (виртуальную реализацию), вы можете использовать базовый класс и переписать метод в некоторых классах (в вашем примере Rule3).

Если вам не нужна стандартная имплементация (виртуальная реализация), вы можете использовать абстрактный базовый класс и переписать метод во всех классах (в вашем примере Rule1, Rule2 и Rule3).

Но это не имеет ничего общего с интерфейсом, который вы хотите использовать.

Полный рабочий пример (только с использованием интерфейса):

using System;
using System.Collections.Generic;

namespace Temp
{
    class Program
    {
        static void Main(string[] args)
        {
            var calc = new Calculator();
            var rules = new List<IRule>() { new Rule1(), new Rule2(), new Rule3() };
            calc.Do(rules);
            Console.WriteLine(calc.GetTotal());
            Console.ReadKey();
        }
    }

    public interface IRule
    {
        float Calc();
    }

    public class Rule1 : IRule
    {
        int type = 1;
        string name = "Rule";
        public float Calc()
        {
            return 1 + 2 + type; // SAME
        }
    }

    public class Rule2 : IRule
    {
        int type = 2;
        string name = "Rule2";
        public float Calc()
        {
            return 1 + 2 + type; // SAME
        }
    }

    public class Rule3 : IRule
    {
        int type = 3;
        string name = "Rule3";
        public float Calc()
        {
            return 3 + 4 + type; // DIFFERENT
        }
    }

    public class Calculator
    {
        private float _total = 0;

        public void Do(List<IRule> ruleList)
        {
            foreach (var rule in ruleList)
            {
                _total += rule.Calc();
            }
        }

        public float GetTotal()
        {
            return _total;
        }
    }
}
...