2009-04-05 2 views
1

Каков наилучший способ вызвать конструктор класса, который может иметь множество параметров, связанных с ним?Конструктор классов с несколькими параметрами

Например, если я хочу разработать компонент для автоматического регистрации исключений в приложении; назовем его «ExceptionLogger»

В ExceptionLogger есть 3 способа записи ошибок, сгенерированных приложением, которое ссылается на него.

ToLogFile    (takes 2 parameters) 
ToDatabase    (takes 2 parameters) 
ToEmail    (take 4 parameters) 

Каждый из этих 3-х методов являются частными для ExceptionLogger и Вызывающее приложение должно «включить» эти методы с помощью класса constuctor; также поставляя параметры, если это необходимо.

Вызывающее приложение просто использует метод «publish», чтобы ExceptionLogger записывал информацию в соответствующее хранилище.

Добавить разъяснение; это мое намерение для одного экземпляра ExceptionLogger, чтобы иметь возможность делать несколько записей

ответ

3

Кажется, что это может быть хорошим местом для использования наследования вместо этого. У вас могут быть FileLogger, DatabaseLogger и EmailLogger, каждый из которых происходит из базового класса ExceptionLogger и имеет один подходящий конструктор.

1

Уточнение, я прочитал ваш вопрос и предположил, что один экземпляр ExceptionLogger может писать через несколько типов связи.

В этом конкретном примере я хотел бы инкапсулировать параметры, необходимые для включения каждого из трех методов письма в отдельный класс. Скажем

  • LogFileConstructionInfo
  • DatabaseConstructionInfo
  • EmailConstructionInfo

Я бы тогда создать 4 разных конструкторов. Один для каждого из вышеуказанных типов принимает только этот тип. Это позволяет быстро и легко создавать экземпляры ExceptionLogger, которые записываются только одним способом. Он также делает код call-сайта очень понятным в отношении того, какой метод он использует.

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

+0

oops! вы совершенно правы, я хотел, чтобы один экземпляр мог выполнять несколько операций записи. – Rob

0

Используйте отдельные классы, которые могут записывать данные в файл журнала/базу данных/электронную почту и передавать тот, который вы хотите использовать в конструкторе. И сделать их все реализовать тот же интерфейс

пример:

LogDatabaseWriter writer = new LogDatabaseWriter(param1, param2, param3); 
Logger log = new Logger(writer); 

редактирования: Некоторый больше кода

Так у вас есть пример интерфейс:

interface ILogWriter 
{ 
    public void Write(string s); 
} 

И несколько реализаций интерфейс

class LogDatabaseWriter : ILogWriter 
{ 
    //constructor 
    // ... 

    //implement the required interface methods 
    public void Write(string s) 
    { 
     //Do your thing 
    } 
} 

И ваш класс Logger имеет конструктор так:

class Logger 
{ 
    private ILogWriter _writer; 

    public Logger(ILogWriter writer) 
    { 
     _writer = writer; 
     //Do your thing 
    } 
} 
2

Вы могли бы хотеть рассмотреть вопрос об использовании Named Constructor парадигмы или три отдельных классов в иерархии. Похоже, у вас есть три разных класса, каждый из которых имеет собственный набор требований к конструктору. Если данные в параметрах конструктора необходимы для работы экземпляра, то они должны быть параметрами конструктора, иначе вы получите экземпляр, в котором отсутствуют данные.

Другой подход заключается в использовании Named Parameters для представления действительно необязательных параметров. Я считаю, что boost предлагает платформу для реализации именованных параметров.

+0

называются параметрами, доступными только в C# 4.0? – Rob

+0

Упс ... У меня была моя C++ шляпа. Затем поцарапайте этот комментарий об Именованных параметрах. Именованные конструкторы по-прежнему являются опцией, но я бы лично пошел с опцией наследования. Это чище. –

0

Если типы хранения не должен быть продлен, я бы рекомендовал использовать перечисление, как этот

public enum StorageLocation 
{ 
    None, 
    File, 
    Database, 
    Email  
} 

public class ExceptionLogger 
{ 
    private StorageLocation m_Storage;  

    public StorageLocation Storage 
    { 
     get { return m_Storage; } 
     set { m_Storage = value; } 
    } 

    // ... 
} 

Если вы считаете, что места хранения должны быть расширены в будущем, то я хотел бы создать интерфейс IStorageLocation и использовать его для получения/установки свойства Storage в ExceptionLogger. Будет немного больше усилий, но вы получите гораздо большую гибкость.

0
  1. Напишите несколько ctors, принимающих разные аргументы.

  2. Сделайте ctor конфиденциальным или защищенным и добавьте три по-разному названные статические функции (например, электронную почту, регистратор, базу данных), которые принимают правильные аргументы и передают их в ctor, а также информацию о том, какой тип EceptionLogger contruct, а затем вернуть вновь созданный объект. Это именованный шаблон-конструктор. http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.8

  3. Как 1, но передайте фиктивный аргумент, чтобы отличить ctors, которые в противном случае имели бы такую ​​же подпись. Один полезный макет - это интерфейсы Marker, определенные в классе. Интерфейс Marker - это тип класса, который ничего не сигнализирует, передавая или используемый в качестве базового класса. например

    public class ExceptionLogger { 
        private class AsEmail {} ; 
        public static AsEmail asEmail; 
        private class AsLogFile {} ; 
        public static AsLogFile asLogFile {}; 
        ExceptionLogger(const AsEmail&, const char* const) ; 
        ExceptionLogger(const AsLogFile&, const char* const) ;
  4. В 3, но отличающем ctors по перечислению и ветви внутри CTOR. (Это один некрасиво.)

  5. Добавить сеттеры к классу, «цепи», возвращая * это, «именованный параметр Фразеологизм»: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.18 Учитывая, что у вас есть дизъюнкция аргументов, а не объединение их, три, вероятно, плохой выбор для ExceptionLogger.

  6. Передача в другом классе, который содержит параметры, класс «Черты».

  7. Сохраняйте общую логику в своем классе, передавайте в логике варианта как (единственную) подсистему GOF ConcreteStrategy из GOF AbstractStrategy. Подобно 3, но теперь логика находится в аргументе.

  8. Сохраняйте общую логику в своем классе, но делайте ее базовым классом из трех отдельных подклассов, которые выделяют различные стратегии, а затем вызывают общие функциональные возможности в базовом классе. В каждом подклассе есть один ctor, но они могут иметь те же аргументы, что и ctors не наследуются.

  9. Сохраняйте общую логику в своем классе, но делегируйте ее из трех несвязанных классов, каждая из которых удерживает ее сдерживанием или как частный базовый класс. Опять же, каждый может иметь свой собственный ctor. Нехорошо, поскольку вы, вероятно, хотите, чтобы ExceptionLoggers имели один и тот же (супер) тип.

Смежные вопросы