TheRedEye Ответов: 2

Вопрос новичка об интерфейсах


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

Пример ниже:
interface IPrinter
{
	string IPAddress { get; set; }
	
	void Print();
}

public class EthernetPrinter : IPrinter
{
	public string IPAddress { get; set; } // IPAddress
	public void Print() { Console.WriteLine("Printing over ethernet"); }
}

public class SerialPrinter : IPrinter
{
	public string IPAddress { get; set; } // Not going to be used. 
	public int CommPort { get; set; } // this is the actual property I need.
	public void Print() { Console.WriteLine("Printing serially"); }
}


А потом использовать его вот так. Но разве я не должен уходить от операторов if с помощью программирования OO?

IPrinter printer;

if (someSetting == "UseEthernet")
    printer = new EthernetPrinter() { IPAddress = "1.1.1.1" };
else
    printer = new SerialPrinter() { CommPort = 1 };

printer.Print();


Что я уже пробовал:

Но потом я вижу, что могу извлечь интерфейсы немного дальше, чтобы использовать соединение для других устройств, но это не намного лучше.
interface IDataSender
{
	void SendData();
}
interface ISerialDataSender : IDataSender
{
	int CommPort { get; set;}
}

interface IEthernetSender : IDataSender
{
	string IPAddress { get; set;}
}

interface IPrinter
{
	void Print();
}

public class EthernetPrinter : IPrinter, IEthernetSender
{
	// this looks good
	public string IPAddress { get; set; }
	public void Print() { Console.WriteLine("Printing over ethernet"); }
	
	// but this feels like this should be in some other class 
	//as this could be pretty generic to any ethernet device.
	public void SendData() 	{ }
}

public class SerialPrinter : IPrinter, ISerialDataSender
{
	// once again, this seems correct
	public int CommPort { get; set; }
	public void Print() { Console.WriteLine("Printing serially"); }

	// but this doesn't.
	public void SendData() {}

}

2 Ответов

Рейтинг:
2

OriginalGriff

Цитата:
Что мне делать, если в моих интерфейсах есть свойства, которые не будут использоваться реализующим классом?

Ты не можешь, вот в чем все дело.

Интерфейсы вообще не могут объявлять никаких конкретных объектов: все, что они могут делать, - это объявлять элементы, которые должны быть реализованы классом, наследующим интерфейс. Если вы попытаетесь объявить свойство в своем интерфейсе и дать ему любое "реальное" определение:
public class EthernetPrinter : IPrinter
    {
    public string IPAddress { get; set; } // IPAddress
    public void Print() { Console.WriteLine("Printing over ethernet"); }
    }
Тогда вы получите ошибку компиляции.
Если вам не удастся реализовать это свойство в производных классах, вы также получите ошибку компиляции.

Если вам нужны конкретные объекты, то вы используете абстрактный класс.


Рейтинг:
18

F-ES Sitecore

Интерфейс - это просто гарантия того, что класс реализует свойства\методы на интерфейсе, хотя ничто не мешает классу использовать другие свойства и методы. Поэтому я бы сократил ваш интерфейс IPrinter только до метода печати.

interface IPrinter
{
	void Print();
}

public class EthernetPrinter : IPrinter
{
	public string IPAddress { get; set; }
	public void Print() { Console.WriteLine("Printing over ethernet"); }
}

public class SerialPrinter : IPrinter
{
	public int CommPort { get; set; }
	public void Print() { Console.WriteLine("Printing serially"); }
}


Ваш существующий код все равно будет работать

IPrinter printer;

if (someSetting == "UseEthernet")
    printer = new EthernetPrinter() { IPAddress = "1.1.1.1" };
else
    printer = new SerialPrinter() { CommPort = 1 };

printer.Print(); // no matter what branch the "if" takes above you know that the object referenced by "printer" has a Print method and that's all you need to know


Что касается вашего метода "если", то если вы загуглите заводской шаблон, который покажет вам, как вы можете справиться с этим. У вас все еще будет "если", но оно будет скрыто внутри фабричного класса, который оставит ваш основной код более чистым.