Передача производного класса в качестве параметра методу, когда тип параметра является базовым классом - PullRequest
42 голосов
/ 04 января 2011

Я новичок и пытаюсь понять концепции наследования и шаблонов проектирования.

Я наткнулся на этот шаблон http://en.wikipedia.org/wiki/Strategy_pattern, когда просматривал какой-то блог.

Я нашел это интересным и хотел узнать больше. Поэтому я разработал следующую программу.

static void Main(string[] args)
{
    Context context;

    // Three contexts following different strategies
    context = new Context(new ConcreteStrategyAdd());
    int resultA = context.executeStrategy(3, 4);

    context = new Context(new ConcreteStrategySubtract());
    int resultB = context.executeStrategy(3, 4);

    context = new Context(new ConcreteStrategyMultiply());
    int resultC = context.executeStrategy(3, 4);

    Console.Read();
}      

abstract class Strategy
{
    public abstract int execute(int a, int b);

    public void Test()
    {
        Console.Write("tttt");
    }
}

class ConcreteStrategyAdd : Strategy
{
    public override int execute(int a, int b)
    {
        Console.WriteLine("Called ConcreteStrategyAdd's execute()");
        return a + b;  // Do an addition with a and b
    }
}

class ConcreteStrategySubtract : Strategy
{

    public override int execute(int a, int b)
    {
        Console.WriteLine("Called ConcreteStrategySubtract's execute()");
        return a - b;  // Do a subtraction with a and b
    }
}

class ConcreteStrategyMultiply : Strategy
{
    public override int execute(int a, int b)
    {
        Console.WriteLine("Called ConcreteStrategyMultiply's execute()");
        return a * b;   // Do a multiplication with a and b
    }
}

class Context
{
    private Strategy strategy;

    // Constructor
    public Context(Strategy strategy)
    {
        this.strategy = strategy;
    }

    public int executeStrategy(int a, int b)
    {
        return strategy.execute(a, b);
    }
}

Программа отлично компилируется и работает. Но мой вопрос заключается в том, как можно передать производный класс в качестве параметра, когда конструктор Context ожидает базовый класс в качестве параметра? Кастинг происходит неявно? Почему компилятор не выдает ошибку?

context = new Context(new ConcreteStrategyAdd());  

public Context(Strategy strategy)
{
    this.strategy = strategy;
}

Ответы [ 4 ]

30 голосов
/ 04 января 2011

Проще говоря:

Производный класс (или подкласс) является экземпляром своего базового класса.

Итак, когда вы передаете экземпляр ConcreteStrategyAdd в конструктор, вы, по сути, передаете объект Strategy.

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

28 голосов
/ 04 января 2011

Приведение не требуется, поскольку ConcreteStrategyAdd является Стратегией - она ​​удовлетворяет всем требованиям, предъявляемым к Стратегии. Это принцип полиморфизма.

Возможно, нужен более упрощенный пример:

abstract class Fruit { }

class Apple : Fruit { }
class Orange : Fruit { }
class Melon : Fruit { }

class FruitBasket
{
    void Add(Fruit item) { ... }
}

FruitBasket basket = new FruitBasket();
basket.Add(new Apple()); // Apple IS A fruit
basket.Add(new Orange()); // Orange IS A fruit
basket.Add(new Melon()); // Melon IS A fruit

class Potato : Vegetable { }

basket.Add(new Potato()); // ERROR! Potato IS NOT A fruit.
2 голосов
/ 04 января 2011

это легче понять, если вы используете более простой пример, чем шаблон стратегии.

Предположим, у вас есть класс с именем "Fruit" и класс с именем "Apple", производные от фруктов.любой метод, который написан для работы с фруктами в целом, может прекрасно работать с яблоками или фруктами любого другого типа

2 голосов
/ 04 января 2011

Производный класс является базовым классом .(Вот и вся концепция наследования: наследование определяет отношение «является»).

Также ознакомьтесь с принципом замены Лискова :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...