首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从过程到面向对象

从过程到面向对象
EN

Code Review用户
提问于 2020-04-24 15:30:37
回答 1查看 129关注 0票数 1

最近,我在网上阅读了一些博客主题,发现在我的职业生涯中,90%的代码行都是程序化的,而不是面向对象的(大耳光)。所以现在,我试着切除我的大脑,以便只产生OOP代码。问题是我对OOP的练习有很多疑问。

这里有一个:

我得到了一个工厂RawLineCollectionFactory,它使用字符串行并从中创建一个名为RawLineCollection的域实体。我的问题是关于参数类型传递到Create方法。

是否应该传递对象(IDataSource),该对象允许我检索这样的字符串行:

代码语言:javascript
复制
public class RawLineCollectionFactory : IRawLineCollectionFactory
{
    public IRawLineCollection Create(IDataSource dataSource)
    {
        ICollection lineGroup = new List();

        if (dataSource.GetLines() != null)
        {
            foreach (string line in dataSource.GetLines())
            {
                lineGroup.Add(new RawLine(line));
            }
        }

        return new RawLineCollection(lineGroup);
    }
}

还是在更高的抽象级别上调用dataSource对象的D6,并将结果作为Create方法的参数传递?

代码语言:javascript
复制
public class RawLineCollectionFactory : IRawLineCollectionFactory
{
    public IRawLineCollection Create(IEnumerable lines)
    {
        ICollection lineGroup = new List();

        if (lines != null)
        {
            foreach (string line in lines)
            {
                lineGroup.Add(new RawLine(line));
            }
        }

        return new RawLineCollection(lineGroup);
    }
}

编辑:

上下文非常接近应用程序入口点。RawLine是文件中包含游戏创建数据设置的行的对象表示形式。

代码语言:javascript
复制
    public class RawLine
{
    private string value;

    public RawLine(string value)
    {
        this.value = value;
    }

    public IEnumerable Split(string separator)
    {
        if (string.IsNullOrEmpty(separator))
        {
            throw new ArgumentException("The separator is required");
        }

        if (!string.IsNullOrEmpty(value))
        {
            return value
                .Replace(" ", "", StringComparison.CurrentCulture)
                .Split(separator)
                .Where(item => !string.IsNullOrEmpty(item));
        }

        return Array.Empty();
    }
}

该类的行为是为特定于应用程序的规则目的拆分他的状态的实际表示,而RawLineCollection是该实体类型的集合。

代码语言:javascript
复制
    public class RawLineCollection : IRawLineCollection
{
    private readonly IEnumerable lines;
    private readonly string separator = "-";

    public RawLineCollection(IEnumerable lines)
    {
        this.lines = lines;
    }

    public SplittedLineCollection Split()
    {
        ICollection> result = new List>();

        if (IsValidStringGroup(lines))
        {
            foreach (RawLine line in lines)
            {
                if (line.Split(separator).Any())
                {
                    result.Add(line.Split(separator));
                }
            }
        }

        return new SplittedLineCollection(result);
    }

    private bool IsValidStringGroup(IEnumerable settingsToSplit)
    {
        return settingsToSplit != null && settingsToSplit.Any();
    }
}

RawLineCollectionFactory只使用了一次,比如DataSource.GetLines()方法。

EN

回答 1

Code Review用户

回答已采纳

发布于 2020-04-25 22:47:44

谢谢你的问题。IMHO,将过程代码转换为OO代码是一件很好的实践。恭喜你的顿悟!

一般来说,持久化游戏数据的问题是一个序列化问题。我将邀请您探索.NET的本机“设置”功能是否能够满足您的需求。除此之外,标准序列化到JSON或XML可能值得一看。

如果您坚持“滚动您自己的”序列化,您当然可以这样做,以面向对象的方式。我对开始工作的看法如下。

如果您有像游戏级别定义这样的复杂数据,您可能会序列化大量数据,这将更有理由使用标准格式,如JSON或XML。

为了序列化和反序列化一个相对简单的配置文件,您可能可以跳过工厂模式。但是,如果配置跨越多个文件,包括图像块等,那么"Config Factory“可能是值得考虑的。

我建议构建一个(或多个)类来正确地建模实际的配置属性,并将其序列化/反序列化,而不是将所有内容作为字符串处理。

例如:

代码语言:javascript
复制
public class Config
{
    public string PlayerName {get; set;}
    public DateTime LastPlayed {get; set;}
    public int HighScore {get; set;}
} 

下面的例子采用“混合”方法。它不仅仅是使用KeyValuePair来处理原始字符串,而是停止了一个完全类型的Config类(如上面所示)。

另一个快速提示:与RawLineCollection不同,我称它为RawLines,甚至更好的是,Lines

欢迎来到广阔的OOP世界。在我的其他一些代码评审答案中,我深入探讨了指导我的OOP实践的原则。

下面是示例(这段代码编译,但我没有测试它):

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

public class App_ConfigFile
{
    /*  Config file example 

        player1Name:Jane
        player2Name:Joe
        difficulty:medium
        lastPlayed:04/20/2020
        lastLevel:5
        highScore:31000
     */

    public void Run()
    {
        var file = new ConfigFile(@"c:\myGame\config.txt");
        var config = file.ToConfigData();
        var player1name = config.GetByName("player1Name");
        var lastPlayed = DateTime.Parse(config.GetByName("lastPlayed"));
        var highScore = int.Parse(config.GetByName("highScore"));
    }
}

public class ConfigFile
{
    private string path;
    private List lines;
    public List Lines => lines ?? (lines = getLines());
    public bool HasContent => Lines.Count > 0;

    public ConfigFile(string path) => this.path = path;

    public ConfigData ToConfigData(char separator = ':') => new ConfigData(Lines.Select(l => l.ToKvp(separator)).ToList());

    private List getLines() => File.ReadAllLines(path).Select(l => new Line(l)).ToList();
}

public class Line
{
    public string Raw { get; private set; }
    public Line(string line) => Raw = line;

    public KeyValuePair ToKvp(char separator)
    {
        var tokens = Raw.Split(separator);
        return new KeyValuePair(tokens.First(), tokens.Last());
    }
}

public class ConfigData
{
    private List> data;
    private Dictionary _dictionary;
    private Dictionary dictionary => _dictionary ?? (_dictionary = data.ToDictionary(d => d.Key, d => d.Value, StringComparer.OrdinalIgnoreCase));

    public ConfigData(List> data) => this.data = data;

    public string GetByName(string key) => dictionary[key];
    public bool TryGetByName(string key, out string value) => dictionary.TryGetValue(key, out value);
}

}

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

https://codereview.stackexchange.com/questions/241148

复制
相关文章

相似问题

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