Должен ли я создать отдельный класс для этого? - PullRequest
2 голосов
/ 03 декабря 2009

Мой проект содержит много классов, кучу которых можно описать с помощью файлов XML. Не волнуйтесь, это не логика или реализация в XML. Это игра, и примером может служить определение игрового тайла в XML, файла изображения, кадров анимации и т. Д.

В итоге у меня будет куча функций, которые выглядят так:

public static Foo FromXml(ref XmlTextReader reader) { ... }

Вопрос заключается в следующем: должны ли эти функции содержаться в своем собственном соответствующем классе, например, приведенным выше будет Foo.FromXml. Или я должен сделать отдельный класс для чтения вещей из файлов? Кажется, здесь конкурируют два основных принципа:

  1. Класс должен знать все об одной вещи - о себе.
  2. У класса должна быть только одна причина для изменения.

Прежде всего, я не совсем понимаю второй, потому что «причина» довольно расплывчата. Первое руководство предлагает поместить каждого читателя в соответствующий класс. Второй говорит сделать один класс, предназначенный для чтения XML-файлов. Но плюсы и минусы спорны. С одной стороны, каждый класс может содержать своего собственного читателя, так что на него не ссылаются дюжина классов. С другой стороны, каждый класс должен включать System.Xml, и если я изменю свой формат xml, вещи могут измениться в нескольких файлах (но я не думаю, что это слишком плохо).

Я знаю, что самое важное правило - это «использовать свой мозг», и не существует такого понятия, как «правильное» решение, только хорошее и работающее. Так что, по вашему мнению, было бы более читабельным или еще лучше поддерживаемым?

изменить: уточнить, классы могут быть совершенно не связаны. Так как это игра, то может быть классом спрайтовой анимации, кто-то может определять поведение врага, кто-то может определять макет или свойства карты. Так что наследование не имеет к этому никакого отношения.

Ответы [ 2 ]

2 голосов
/ 03 декабря 2009

Функции FromXml (...) идентичны? Предполагая, что они есть, я бы поместил их в общую библиотечную область, потому что это значительно облегчит их обслуживание, поскольку не будет дублирования кода. Код все еще должен быть аккуратным

SomeObject o = (SomeObject)Foo.FromXml(reader);

РЕДАКТИРОВАТЬ: Или, возможно, создать некоторый базовый абстрактный класс, который просто имеет функции FromXml / ToXml, а затем все классы, которые хотят использовать эти функции, наследуются от абстрактного класса.

1 голос
/ 03 декабря 2009

иметь статический метод базового класса для всех наследуемых классов и поддерживать правильный полиморфизм сложно. Однако вы можете удалить статичность метода и иметь метод InitializeFromXml, который, по сути, позволит вам заполнить ваш класс из XML. Хотя мне, как правило, наплевать на публичные методы инициализации, это лучше для полиморфизма.

вот пример. это немного для маленького объекта, подобного этому (и я редко когда-либо фактически использую сериализацию xml, но загружаю его в документ xml и извлекаю то, что мне нужно для назначений десериализации), но когда вещи масштабируются, наследуются, и обычно сложный, он позволяет использовать еще немного больше:

public class CustomObject {
    public string AValue { get; set; }
    public bool BValue { get; set; }
    protected IXmlConfiguration Config = new CustomObjectConfig( );

    public virtual string ToXml( ) {
        return Config.ToXml( this );
    }

    public virtual void InitializeFromXml( string xml ) {
        Config.FromXml( xml );
        AValue = ((CustomObjectConfig)Config).A;
        BValue = ((CustomObjectConfig)Config).B;
    }
}

public interface IXmlConfiguration {
    void FromXml( string xml );
    string ToXml( object instance );
}

[XmlRoot( "CustomObject" )]
public class CustomObjectConfig : IXmlConfiguration {
    [XmlElement( "AValue" )]
    public string A { get; set; }
    [XmlAttribute( "bvalue" )]
    public bool B { get; set; }

    public void FromXml( string xml ) {
        byte[] bytes = Encoding.UTF8.GetBytes( xml );
        using ( MemoryStream ms = new MemoryStream( bytes ) ) {
            XmlSerializer xs = new XmlSerializer( typeof( CustomObjectConfig ) );
            CustomObjectConfig cfg = (CustomObjectConfig)xs.Deserialize( ms );
            A = cfg.A;
            B = cfg.B;
        }            
    }

    public string ToXml( object instance ) {
        string xml = null;
        if ( instance is CustomObject ) {
            CustomObject val = (CustomObject)instance;
            A = val.AValue;
            B = val.BValue;
            using ( MemoryStream ms = new MemoryStream( ) ) {
                XmlSerializer xs = new XmlSerializer( typeof( CustomObjectConfig ) );
                xs.Serialize( ms, this );
                ms.Seek( 0, 0 );
                byte[] bytes = ms.ToArray( );
                xml = Encoding.UTF8.GetString( bytes );
            }
        }
        return xml;
    }
}

Причина, по которой я предпочел бы этот подход, а не создание сериализуемых объектов XML, заключается в том, что

  1. XML сериализация обычно требует Вы структурируете свой класс одним способом, и вы обычно будете использовать это Класс по-другому.
  2. это немного проще, чем иметь огромный стеки xml включают атрибуты (можно назвать что-то другое) везде, где бы полиморфная сериализация производного типы.
...