Принуждение реализаций интерфейса для реализации иерархии в c # - PullRequest
4 голосов
/ 26 июня 2009

Я пишу интерфейсы для нового проекта и хотел бы получить совет.

У меня есть класс, у которого есть подкласс, и у него есть подкласс. Дерево этого класса выглядит так:

Class Car
{
    Wheels Wheel;
}
Class Wheels
{
    Rims Rim;
}

Итак, чтобы упростить: одна машина имеет одно колесо, а одно колесо имеет один обод. (не могу придумать другой лучший пример, извините).

Итак, я хотел бы использовать эту иерархию в моей реализации интерфейса ICar, IWheels и IRims.

Итак, я сделал что-то вроде этого (в C #):

ICar
{
  IWheels Wheel;
}
IWheels
{
  IRims Rim;
}

И у меня есть ошибка, что я не могу иметь поля в реализации интерфейса. Так что это заставило меня задуматься о том, что, возможно, это неправильный дизайн интерфейса. Я хотел бы заставить реализации интерфейса реализовать такую ​​иерархию. Но, может быть, в соответствии с шаблонами проектирования и лучшими практиками, это должно быть сделано по-другому?

Не могли бы вы сказать мне, как спроектировать мою систему, чтобы объекты были вынуждены реализовать такую ​​иерархию?

Возможно, в моем вопросе что-то неточное, или я упустил какую-то важную информацию. Если да, пожалуйста, спрашивайте в комментариях.

Ответы [ 6 ]

10 голосов
/ 26 июня 2009

В вашем интерфейсе вам нужно прояснить, что Wheels должен быть свойством ICar, так как вы не можете указать, какие поля должна иметь реализация интерфейса. (Поля являются внутренней работой, поэтому интерфейс не должен знать об этом).

interface ICar
{
    IWheels Wheels
    {
       get;
    }
}
7 голосов
/ 26 июня 2009

Вы не можете указать поле в интерфейсе (и вы не можете - это решение по реализации), но вы можете указать свойство :

public interface ICar
{
    IWheels Wheel { get; set; }
}

public interface IWheels
{
    IRims Rim { get; set; }
}

Возможно, вы захотите добавить в интерфейс только геттер - немного необычно включать сеттер в интерфейс:

public interface ICar
{
    IWheels Wheel { get; }
}

public interface IWheels
{
    IRims Rim { get; }
}

(Существуют странности, если вы хотите переопределить существующее (или абстрактное) свойство, у которого есть только геттер для добавления сеттера, но, я думаю, можно реализовать интерфейс «только для геттера» с сеттерами.)

4 голосов
/ 26 июня 2009

Вы не можете объявить поля, но вы можете объявить свойства. Это будет иметь тот же конечный эффект, когда вы заставляете определенный класс предоставлять экземпляр другого класса.

ICar
{
  IWheels Wheel { get; set; }
}
IWheels
{
  IRims Rim { get; set; }
}
4 голосов
/ 26 июня 2009

Как говорит ошибка, вы не можете указывать поля в своих интерфейсах. Вы можете указать свойства, хотя:

interface ICar
{
    IWheels Wheel { get; set; }
}

interface IWheels
{
    IRims Rim { get; set; }
}
0 голосов
/ 26 июня 2009

Вот это полнофункциональный код ... Надеюсь, это поможет ...

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication10
{
    //Interfaces

    public interface ICar
    {
        string name { get;}
        IWheel wheel { get;}
    }


    public interface IWheel
    {
        string brand { get;}
    }

    //Implementations

    public class Michelin : IWheel
    {
        #region IWheel Members

        public string brand
        {
            get { return "michelin"; }
        }

        #endregion
    }


    public class Toyota : ICar
    {
        Michelin m = new Michelin();
        #region ICar Members

        public string name
        {
            get { return "toyota"; }
        }

        public IWheel wheel
        {
            get { return m; }
        }

        #endregion
    }

    //A user of the interfaces. Only cares about ICar but knows implicitly about IWheel

    public class Stand
    {
        public Stand()
        {
            cars = new List<ICar>(2);
            cars.Add(new Toyota());
            cars.Add(new Toyota());
        }
        List<ICar> cars;

        public string ShowCars()
        {
            StringBuilder str = new StringBuilder();
            foreach (ICar iterCar in cars)
            {

                str.AppendLine(string.Format("car {0} with wheel {1}",
                    iterCar.name, iterCar.wheel.brand));
            }
            return str.ToString();
        }
    }

    //entry point. creates a stand and shows the cars, testing that properties are visible
    class Program
    {
        static void Main(string[] args)
        {
            Stand myLittleStand = new Stand();
            Console.WriteLine(myLittleStand.ShowCars());
        }
    }
}
0 голосов
/ 26 июня 2009

Я не так привык к C #, но мне кажется, что вы можете форсировать эту реализацию, создавая абстрактные классы с полями, которые вы хотите использовать. Поэтому, если вы расширите эти абстрактные классы, у вас будут в них доступные поля. Вы должны будете сделать абстрактный класс И интерфейс, хотя ...

...