首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在同一类型上实现多个接口的模式是什么?

在同一类型上实现多个接口的模式是什么?
EN

Software Engineering用户
提问于 2017-05-18 19:21:13
回答 2查看 2.8K关注 0票数 1

环境描述:

  • 我正在为(一个老的) PlayStation 1电子游戏实现一个(爱好者)现代引擎。
  • 图形数据表示为数据包,可以表示多边形或精灵、 (它们被不同地转换成屏幕上的像素)。
  • 实际上,所有这些不同类型的数据包(总共18个)最多可以减少到2或3个类型(我为减少代码面所做的工作),并有一些标志指示它们中存在什么。

以供参考,

这种格式或多或少是索尼HMD格式的变体,这是一种高效的低级别格式,直接由PlayStation 1 GPU使用,代价是不友好地读取/解析等.(实际上,在实际的PlayStation 1上,很少会发出系统库调用来加载它,就是这样)

对问题的描述:

  • 我需要找到一种(简单而有效的)方法来实现它们的内容。
  • 他们既可以是多边形,也可以是精灵

长话短说,

下面的代码片段可能更好地解释了内容和初步方法,

我们将针对的

接口:

代码语言:javascript
运行
复制
/// <summary>
///     a graphics primitive.
/// </summary>
public interface IPrimitive
{
    bool IsPolygon { get; }
    bool IsSprite { get; }
}

/// <summary>
///     a polygon, i.e. triangle, quad.
/// </summary>
public interface IPolygon : IPrimitive
{
    void GetMesh();
}

/// <summary>
///     a sprite, (internal representation has different meaning than a polygon).
/// </summary>
public interface ISprite : IPrimitive
{
    void GetMesh();
}

游戏数据中的

类型:

代码语言:javascript
运行
复制
/// <summary>
///     a packet representing graphical data : a polygon or a sprite.
/// </summary>
public class GraphicsPacket : IPolygon, ISprite
{
    public GraphicsPacket(Stream stream)
    {
        // read packet ...


        // there will be a flag indicating if it's a sprite
        // and therefore should be treated differently
    }

    public bool IsSprite { get; }

    public bool IsPolygon => !IsSprite;

    void IPolygon.GetMesh()
    {
        if (IsSprite)
            throw new InvalidOperationException("Instance is not a polygon");
    }

    void ISprite.GetMesh()
    {
        if (IsPolygon)
            throw new InvalidOperationException("Instance is not a sprite");
    }
}

整个逻辑的

测试:

代码语言:javascript
运行
复制
public class Test
{
    public void BuildPrimitive([NotNull] IPrimitive primitive)
    {
        if (primitive == null)
            throw new ArgumentNullException(nameof(primitive));

        // obviously here, 'as' cast would always be true for all cases

        var polygon = primitive.IsPolygon;
        if (polygon)
        {
            // do something with it
            ((IPolygon)polygon).GetMesh();

            return;
        }

        var sprite = primitive.IsSprite;
        if (sprite)
        {
            // do something with it
            ((ISprite)sprite).GetMesh();

            return;
        }

        throw new NotSupportedException(nameof(primitive));
    }
}

问题:

根据图形包的内容,我的处理方法是好的吗?

  • 显式接口实现
  • 无效状态的朴素bool检查和抛出

强烈主张在这种情况下考虑分开关注,

  • 游戏数据就是这样,为什么要改变逻辑呢?
  • (I)现代的面向对象的方法,将其概括为几种类型(即干概念)。
  • 问题不会真的消失,因为这些图形包总是一个多边形或一个精灵(也就是说,为什么要与这种逻辑作斗争呢?)

希望这对你来说是有意义的,否则让我知道如何改进这个问题。

EN

回答 2

Software Engineering用户

发布于 2017-05-18 19:50:07

我相信你只需要一个接口,类为多边形和雪碧实现。基于我所看到的,我将为GraphicsPacket创建一个接口,并创建实现其方法的Polygon和Sprite类。

然后,在整个代码中,您只需编写它就可以使用GraphicsPacket对象,您不需要多次决定它是多边形还是雪碧。

代码语言:javascript
运行
复制
public interface IGraphicsPacket
{
    public GraphicsPacket(Stream stream);

    public GetMesh()
}

public class  Polygon : IGraphicsPacket
{
    public GraphicsPacket(Stream stream)
    {
        //Polygon implementation
    }

    public GetMesh()
    {
        //Polygon implementation
    }
}

public class  Sprite : IGraphicsPacket
{
    public GraphicsPacket(Stream stream)
    {
        //Sprite implementation
    }

    public GetMesh()
    {
        //Sprite implementation
    }
}

测试

代码语言:javascript
运行
复制
public class Test
{
    public void BuildPrimitive([NotNull] IGraphicsPacket primitive)
    {
        if (primitive == null)
            throw new ArgumentNullException(nameof(primitive));

        primitive.GetMesh();

        return;
    }
}
票数 2
EN

Software Engineering用户

发布于 2017-06-17 23:51:58

实际上,您在代码中不尊重don原则,因为您总是显式地测试类型.

这是一个很好的例子,在这个例子中,某人应该像jdobrzen在另一个答案中建议的那样使用类层次结构。

避免代码重复的方法是在基类或助手类中共享实现。

代码语言:javascript
运行
复制
public class PrimitiveBase 
{ 
    /* contains common code, probably with protected */
}

public class Polygone : PrimitiveBase, IPolygone { ... }

然后,您还应该有一个工厂方法,它将从流创建适当的对象。一种方法是,您的所有接口都来自IPrimitive,并有一个工厂。

类似于:

代码语言:javascript
运行
复制
public class PrimitiveFactory
{
    IPrimitive CreateFromStream(Stream stream)
    {
        // - Read primitive type from stream
        // - Reset stream position (if necessary)
        // - Create appropriate primitive (might be a switch statement)
        // - If data loading is separate from constructor, then load data
    }
}    

如果需要,可以使用DI容器或序列化框架.

票数 0
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/349231

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档