可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am having trouble with the concept of interfaces interacting with polymorphic types (or even polymorphic interfaces). I'm developing in C# and would appreciate answers staying close to this definition, although i think that still gives plenty of room for everyone to put forth an answer.
Just as an example, let's say you want to make a program to paint things. You define an interface for the actor that Paints, and you define an interface for the subject which is painted, Furthermore you have some subjects which can be painted in a more specific way.
interface IPainter {
void paint(IPaintable paintable);
}
interface IPaintable {
void ApplyBaseLayer(Color c);
}
interface IDecalPaintable : IPaintable {
void ApplyDecal(HatchBrush b);
}
I can imagine making a painter similar to the following:
class AwesomeDecalPainter : IPainter
{
public void paint(IPaintable paintable) {
IDecalPaintable decalPaintable = (IDecalPaintable)paintable;
decalPaintable.ApplyBaseLayer(Color.Red);
decalPaintable.ApplyDecal(new HatchBrush(HatchStyle.Plaid, Color.Green));
}
}
Of course this will throw if paintable does not implement IDecalPaintable. It immediately introduces a coupling between the IPainter implementation and the IPaintable that it operates on. However I also don't think it makes sense to say that AwesomeDecalPainter is not an IPainter just because it's use is limited to a subset of the IPaintable domain.
So my question is really four-fold:
- Are interface compatible with
polymorphism at all?
- Is it good
design to implement an IPainter that
can operate on IDecalPaintable?
- What about if it can exclusively operate
on IDecalPaintable?
- Is there any literature or source code that
exemplifies how interfaces and polymorphic types
should interact?
回答1:
The interface of a class is meant as a tool for the "user" of that class. An interface is a public presentation for the class, and it should advertise, to anyone considering to use it, what methods and constants are available and accessible from the outside. So, as it name suggests, it always sits between the user and the class implementing it.
On the other hand, an abstract class is a tool aimed at helping the "implementor" of the classes that extend it. It is an infrastructure that can impose restrictions and guidelines about what the concrete classes should look like. From a class design perspective, abstract classes are more architecturally important than interfaces. In this case, the implementor sits between the abstract class and the concrete one, building the latter on top of the former.
So to answer your question simply, Interface is a "contract" for the code to respect. When uused this way, it applies more to inheritance that polymorphism.
Abstract classes, they define a 'type'. And when the concrete sub classes use abstract classes and redefine methods, add new ones etc ... there you see polymorphism in action.
I know this post may confuse you more, it didn't make sense to me until I learned design patterns. With a few simple patterns under your belt you will better understand the role of each object and how inheritance, polymorphism and encapsulation play hand in hand to build cleanly designed applications.
Good-Luck
回答2:
Interfaces are not only compatible with polymorphism--they're essential to it. Part of the idea you seem to be missing is that if one has an interface like IPaintable, the expectation is that every object that implements it will provide some default method of being painted, typically encapsulating other methods which would configure the object in some useful fashion.
For example, an IPaintable interface might define a paint method:
void Paint(ICanvas canvas);
Note that the Paint method says nothing about what should be painted, nor what color, nor anything else. Various paintable objects would expose properties to control such things. A Polygon method, for example, might dispose OutlineColor and FillColor properties, along with a SetVertices() method. A routine that wants to paint a whole lot of objects could accept an IEnumerable(Of IPaintable) and simply call Paint on all of them, without having to know anything about how they'll be painted. The fact that an object is painted by calling Paint with no parameters other than the canvas upon which it should be painted in no way prevents the Paint method from doing all sorts of fancy gradient fills, texture mapping, ray tracing, or other graphical effects. The code which is commanding the painting would know nothing of such things, but the IPaintable objects themselves would hold all the information they needed and thus wouldn't need the calling code to supply it.
回答3:
The problem is really that you have defined a vague interface, a contract is a more proper term. It's like you go into McDonalds and just order a burger:
interface Resturant
{
Burger BuyBurger();
}
The person taking your order will look a bit confused for a while, but eventually he/she will serve you any burger since you don't specify what you want.
Same thing here. Do you really just want to define that something is paintable? If you ask me, it's like asking for trouble. Always try to make interfaces as specific as possible. It's always better to have several small specific interfaces than a large general one.
But let's go back to your example. In your case, all classes only have to be able to paint something. Therefore I would add another more specific interface:
interface IPainter
{
void Paint(IPaintable paintable);
}
interface IDecalPainter : IPainter
{
void Paint(IDecalPaintable paintable);
}
interface IPaintable
{
void ApplyBaseLayer(Color c);
}
interface IDecalPaintable : IPaintable
{
void ApplyDecal(HatchBrush b);
}
class AwesomeDecalPainter : IDecalPainter
{
public void Paint(IPaintable paintable)
{
IDecalPaintable decalPaintable = paintable as IDecalPaintable;
if (decalPaintable != null)
Paint(decalPaintable);
else
paintable.ApplyBaseLayer(Color.Red);
}
public void Paint(IDecalPaintable paintable)
{
paintable.ApplyBaseLayer(Color.Red);
paintable.ApplyDecal(new HatchBrush(HatchStyle.Plaid, Color.Green));
}
}
I would recommend that you read about the SOLID principles.
Update
A more sound interface implementation
interface IPaintingContext
{
//Should not be object. But my System.Drawing knowledge is limited
object DrawingSurface { get; set; }
}
interface IPaintable
{
void Draw(IPaintingContext context);
}
class AwesomeDecal : IPaintable
{
public void Draw(IPaintingContext paintable)
{
// draw decal
}
}
class ComplexPaintableObject : IPaintable
{
public ComplexPaintableObject(IEnumerable<IPaintable> paintable)
{
// add background, border
}
}
Here you can create as complex painting items as possible. They are now aware what they paint on, or what other paintables are used on the same surface.
回答4:
Am I understanding your question correctly?
I think your question is whether interface can exercise the essentials of inheritance ?
(ie. child interface inheriting from parent interface).
1) if that's the case, syntactically sure, why not?
2) as for the practicability, it may be of little value because, your child interfaces are not essentially reusing anything from your parent interface.