我有几个名为ShapeA,ShapeB,ShapeC等的C#类和名为ShapeCollection的集合类。它们都继承自一个名为Geometry的抽象类。 所有这些课程都来自第三方集会,所以我无法改变它们。
我想为所有这些Shape类添加一个新方法,让我们称之为Paint()
,并以不同的方式为每个Shape类实现此方法。 ShapeCollection类只会在集合中的每个shape类上调用此Paint()
方法。
我想到的最直接的方法是为每个将继承原始形状类的形状类创建一个新类,但也将实现一个包含Paint()
方法的接口。 / p>
我真的试图避免为每个形状创建一个派生类型,因为有很多形状类。
这样做的正确方法是什么?
答案 0 :(得分:2)
为什么不使用扩展方法?
namespace YourProject.Extensions
{
public static class ShapeExtensions
{
public static void Paint(this ShapeA shape)
{
// Your paint code
}
public static void Paint(this ShapeB shape)
{
// Your paint code
}
public static void Paint(this ShapeC shape)
{
// Your paint code
}
}
}
然后就不需要创建一个继承自Shape
类的新类。
然后在你的ShapeCollection
中,你可以正常调用这些方法(记住包含扩展方法在using语句中所在位置的命名空间)。
<强>更新强>
只是为了满足评论家的要求 - 这只有在你自己处理实际课程时才有效。即如果你在做:
ShapeA shape = new ShapeA();
shape.Paint(); // This will work
可是:
Geometry shape = new Shape();
shape.Paint(); // This will not exist
扩展方法仅在您直接使用该类时才可见。
答案 1 :(得分:1)
此处decorator Pattern可能很有用。这并没有解决许多实施课程的问题。
答案 2 :(得分:1)
我尝试将其放在对GenericTypeTea的答案的评论中,但格式不正确。
难道你不能用这个公认的丑陋的额外扩展方法解决问题吗?在这一点上,它变得非常绝望,你真的不应该害怕创建额外的课程。
public static void Paint(this Geometry shape)
{
if (shape is ShapeA)
((ShapeA)shape).Paint();
else if (shape is ShapeB)
((ShapeB)shape).Paint();
else if (shape is ShapeC)
((ShapeC)shape).Paint();
else
throw new InvalidOperationException("Can't paint " + shape.GetType().FullName);
}
或者你可以用简单的类层次结构和工厂方法来整理丑陋。
interface IShapePainter
{
void Paint(Geometry shape);
}
static class ShapeExtensions
{
public static IShapePainter GetPainter(Geometry shape)
{
if (shape is ShapeA)
return new ShapeAPainter();
// Add other painters here
else
return null;
}
public static void Paint(this Geometry shape)
{
GetPainter(shape).Paint(shape);
}
}
abstract class ShapePainter<T> : IShapePainter
where T : Geometry
{
public abstract void Paint(T shape);
void IShapePainter.Paint(Geometry shape)
{
this.Paint((T)shape);
}
}
class ShapeAPainter : ShapePainter<ShapeA>
{
public override void Paint(ShapeA shape)
{
// Your paint code
}
}
然后,您需要使用ShapePainter的每个实现更新GetPainter,这些实现对应于您可以绘制的所有形状。泛型类并不是绝对必要的,因为您可以直接在ShapeAPainter上实现接口,但每次实现时都可以节省重复的转换。