使用OOP正确处理抽象逻辑中的类型相关逻辑(高度多态对象)

时间:2017-12-07 16:07:13

标签: c# oop

从OOP的角度来处理从Game对象到GameDto对象的映射的最佳方法是什么,考虑到Game的属性Scoreboard有很多派生对象(超过15个)作为FootballScoreboard,Formula1Scoreboard,BaseballScoreboard等?

只有在运行时才有能力知道游戏内部的记分板的确切类型(它可以用于任何运动)。 ScoreboardDto有相应的FootballScoreboardDto,Formula1ScoreboardDto,BaseballScoreboardDto等等。

简化方案:

public class Game 
{
    public Scoreboard Scoreboard { get; }
}

public class GameDto
{
    public ScoreboardDto Scoreboard { get; }
}


public class DtoParser 
{
    public GameDto Parse(Game game)
    {
        var gameDto = new GameDto();
        //How to implement parsing of game.Scoreboard in the best way here????
    }
}

主要目标是避免if-else链和switch-case,因为它在OOP中是不好的做法。

我看到的可能的解决方案: 使用某种ScoreboardParserFactory,根据记分牌类型返回必要的记分板解析器。 像:

var parser = _scoreboardParserFactory.Create(game.Scoreboard);
gameDto.Scoreboard = parser.Parse(game.Scoreboard);

但仍有缺点:
1)看起来我仍然不能仅使用IoC进行任何实现,而且不需要if-else / switch-case,如下所示:

if (scoreboard.GetType() == typeof(FootballScoreboard)) return new FootballScoreboardParser()
else if (scoreboard.GetType() == typeof(Formula1Scoreboard)) return new Formula1ScoreboardParser()
else ...

2)我仍然需要在解析器的Parse方法中进行显式类型转换,如:

public class FootballScoreboardParser
{
    public ScoreboardDto Parse(Scoreboard scoreboard) 
    {
        var footballScoreboard = (FootballScoreboard) scoreboard;
        return new FootballScoreboardDto() {/*...*/};
    }
}

有没有更好的方法来实现高质量OOP代码的转换(没有明确的类型转换和长if-else / switch-case)?也许有任何标准的处理此类案件的方法? IoC对此有何帮助?

1 个答案:

答案 0 :(得分:0)

您可以使用通用接口来实现:

public class DtoParserFactory
{
    private Dictionary<Type, IDtoParser> _parsers = new Dictionary<Type, IDtoParser>();

    public void Register(Type type, IDtoParser parser)
    {
        _parsers.Add(type, parser);
    }

    public IDtoParser GetParser(IScoreBoard scoreBoard)
    {
        var type = scoreBoard.GetType();
        var parser = _parsers[type];
        return parser;
    }
}

public class SomeScoreboardParser : BaseScoreBoardParser<SomeScoreboard, ScoreboardDto>
{
    public override ScoreboardDto Parse(SomeScoreboard scoreBoard)
    {
        return new ScoreboardDto();
    }
}

public abstract class BaseScoreBoardParser<TScoreBoard, TDto> : IDtoParser<TScoreBoard, TDto> where TScoreBoard : IScoreBoard where TDto: IDto
{
    public abstract TDto Parse(TScoreBoard scoreBoard);
    public IDto Parse(IScoreBoard scoreBoard)
    {
        return Parse((TScoreBoard)scoreBoard);
    }
}

public interface IDtoParser<TScoreBoard, TDto> : IDtoParser
    where TScoreBoard : IScoreBoard
    where TDto : IDto
{
    TDto Parse(TScoreBoard scoreBoard);
}

public interface IDtoParser
{
    IDto Parse(IScoreBoard scoreBoard);
}

public class ScoreboardDto : IDto
{

}

public interface IDto
{

}

然后消耗它:

var game = new Game();            
DtoParserFactory factory = new DtoParserFactory();
factory.Register(typeof(SomeScoreboard), new SomeScoreboardParser());
var parser = factory.GetParser(game.Scoreboard);
var dto = parser.Parse(game.Scoreboard);

您只需在工厂注册您的类型,它就会为您解决。这是在代码示例中执行此操作的行:

factory.Register(typeof(SomeScoreboard), new SomeScoreboardParser());

这显然是我在飞行中写的一个过于简单的例子。有一些事情可以改进。这只是为了说明这一点。