Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Печать результатов деятельности класса


Автор: Tror 26.9.2007, 16:56
Доброго дня всем smile
Не знаю отражает ли название темы ее суть, но ничего другого в голову не пришло.

Идея следующая:
Есть несколько классов (порядка 10)
у всех должна быть возможность выводить свои результаты на несколько устройств(консоль, файл, .......)
причем с возможностью настройки формата вывода. Была конечно идея создать интерфейс IPrintable

public IPrintable
{
    void PrintToConsole();
    void PrintToFile();
    void PrintToSmthElse();
}

но перспектива во всех 10-15 классах реализации во всех этих классах этого интерфейса меня не очень радует
да и к тому же, если у меня появиться необходимость реализовать вывод куда-нибудь еще, придется все переделывать
ниже я представил, как я это себе вижу, но мне кажется что моя реализация тоже далека от идеала.
Подскажите , пожалуйста, может есть более удачный вариант сделать это

Код

public class Man
{
    private string firstName;
    private string lastName;

    private IPrintable output;

    public Man(string fName, string lName, IPrintable outputStream)
    {
        firstName = fName;
        lastName = lName;
        outputStream.Print();
    }

    public void Deal()
    {
        // Что-то делаем с firstName и lastName
        Print();
    }

    private void Print()
    {
        PrintInfo pi = new PrintInfo();

        pi.PrintValues.Add("FN", "Вася");
        pi.PrintValues.Add("LN", "Батарейкин");
    }
}

public class Car
{
    private string model;
    private string engine;

    private IPrintable output;

    public Car(string carModel, string carEngine, IPrintable outputStream)
    {
        model = carModel;
        engine = carEngine;
        outputStream.Print();
    }

    public void Deal()
    {
        // Что-то делаем с model и engine
        Print();
    }

    private void Print()
    {
        PrintInfo pi = new PrintInfo();

        pi.PrintValues.Add("MDL", "Proton");
        pi.PrintValues.Add("ENGN", "v12 2.5l");
    }
}

public interface IPrintable
{
    void Print();
}

public class PrintInfo
{
    private readonly Dictionary<string, string> printValues = new Dictionary<string, string>();

    internal Dictionary<string, string> PrintValues
    {
        get { return printValues; }
    }

    public string this[string key]
    {
        get
        {
            if (printValues.ContainsKey(key))
            {
                return printValues[key];
            }
            else
            {
                return String.Empty;
            }
        }
    }
}

public class TextPrint : IPrintable
{
    private string outputFileName;
    private string outputPattern;
    private PrintInfo printInfo;

    public TextPrint(string fileName, string pattern, PrintInfo pi)
    {
        outputFileName = fileName;
        outputPattern = pattern;
        printInfo = pi;
    }

    public void Print()
    {
        using (StreamWriter sr = new StreamWriter(outputFileName))
        {
            sr.WriteLine(ParsePattern());
        }
    }

    private string ParsePattern()
    {
        string result = String.Empty;

        // Парсинг шаблона. Если на входе имеем шаблон "Имя: $FN$, Фамилия: $LN$",
        // на выходе подставляем данные из printInfo (например printInfo["FN"]), если они там есть.
        // В итоге должно получиться примерно следующее "Имя: Вася, Фамилия: Батарейкин"

        return result;
    }
}


Автор: tol05 26.9.2007, 18:58
а почему бы не сделать для всех классов http://msdn2.microsoft.com/en-us/library/ty01x675.aspx ?
Ты задашь вид серилизуемой информации и будешь серилизовать класс просто в поток. А в зависимости от условий будешь подставлять нужный поток (файл, принтер или еще что-нибудь - все равно это будет какой-то поток).

Автор: Tror 26.9.2007, 19:43
 smile  если бы еще скромненький примерчик ко всему этому.
почитал я про эту сериализацию, но мне не до конца ясно когда она вызывается и мне надо не 
сериализовать объект а на основе шаблона и данных составить результирующую строку.

Автор: tol05 26.9.2007, 21:09
Цитата(Tror @  26.9.2007,  19:43 Найти цитируемый пост)
основе шаблона и данных составить результирующую строку

Все, я понял. Серилизация подразумевает восстановление из потока, а тебе это не нужно.
Да, можно поступить проще. Переопредели в своих классах ToString() и каждый класс сам будет формировать сообщения о своем состоянии. Причем для использования своих шаблонов форматирования нужно и форматтер определить, который подставляется в ToString() и гибко меняется.

1. Создаешь свой FormatProvider (от IFormatProvider), свой CustomFormatter (от ICustomFormatter)
в классы передаешь CustomFormatter (или сразу класс делай наследником ICustomFormatter).
2. Переопределяешь в классе 
string ICustomFormatter.Format (string pattern, Object arg, IFormatProvider myFormatProvider) и 
юзаешь String.Format(myFormatProvider, myPattern, myCar)
в ToString() - перенаправляешь вызов на этот метод. 
Можно сделать перегрузки ToString(ICustomFormatter formatter) и просто ToString() (в этом случае внутри ToString() создаешь свой дефолтный форматтер для каждого класса и юзаешь также)

пример - msdn "IFormatProvider Interface", причем подробный. Его можно легко "испоганить" под свой класс  smile 

Достоинства такого способа:
1. Переопределение ToString() должен делать каждый фанатик мелкософта  smile В этом есть смысл. Подумай, что сейчас выводит Car.ToString()? "Tror.Car"? Нафиг нужно?
2. Никаких лишних интерфейсов, легкий код снаружи, надежный внутри.
3. Универсальность. Получил строку и используешь ее где хочешь.
4. Практически все стандартные классы имеют перегрузки с ToString() -> возможно неявное использование твоего кода, просто пишешь Console.Write(myCar) и все  

да, идея это идея получше, аж самому понравилось smile 

Автор: Tror 27.9.2007, 09:14
Цитата(tol05 @  26.9.2007,  21:09 Найти цитируемый пост)
Можно сделать перегрузки ToString(ICustomFormatter formatter) и просто ToString() (в этом случае внутри ToString() создаешь свой дефолтный форматтер для каждого класса и юзаешь также)


Цитата(Tror @  26.9.2007,  16:56 Найти цитируемый пост)
но перспектива во всех 10-15 классах реализации во всех этих классах этого интерфейса меня не очень радует


не..., для каждого в том то и дело что я не хотел, а вот по поводу первого пунктика посмотрим.

Спасибо за наставление на путь истинный smile.
попробую это все реализовать и выложу что получилось


Цитата(tol05 @  26.9.2007,  21:09 Найти цитируемый пост)
Подумай, что сейчас выводит Car.ToString()? "Tror.Car"?

я не настолько тщеславен чтоб использовать свой ник в неймспейсах  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)