Интерфейс, Абстрактный или Наследование? Вопрос о дизайне C # - PullRequest
0 голосов
/ 07 октября 2010

У меня есть таблица, в которой находятся две сущности: StaticProgram и DynamicProgram .В этой таблице есть один столбец с именем ProgramType, который определяет, имеет ли программа тип «Статический» или «Динамический».Хотя эти две сущности хранятся в одной таблице (я полагаю, потому что примитивные поля для статических и динамических программ абсолютно одинаковы), но с точки зрения бизнеса это две ОЧЕНЬ разные сущности.

Итак, ясоздано два класса StaticProgram и DynamicProgram .Однако я не хочу создавать два отдельных класса доступа к данным, потому что это будет точно такой же код, реплицированный дважды.Я попытался создать класс «Program» в качестве базового класса и унаследовал классы StaticProgram и DynamicProgram, но преобразование с понижением не поддерживается, поэтому я не могу вернуть объект «Program» из класса доступа к данным и привести его к классу «StaticProgram» и т. Д.

Итак, каковы мои варианты?Могу ли я создать интерфейс IProgram и иметь StaticProgram и DynamicProgram для реализации этого интерфейса и получить мой класс доступа к данным, возвращающий IProgram ?Или как насчет того, чтобы сделать метод доступа к данным универсальным методом (если это возможно и является рекомендуемым подходом, мне потребуется некоторая помощь, поскольку у меня нет большого опыта работы с генериками)?Любые другие предложения?

Буду признателен за вашу помощь !!

Обновление: Метод доступа к данным действительно статический:

public static class ProgramDataMapper
{
    public static Program GetProgram(int programID)
    {
        Program p = new Program();
        // database stuff
        p.Name = reader["Name"].ToString();
        ...
        return p;
    }
}

Базовый классвыглядит так:

public class Program
{
    // Properties

    public static Program GetProgram(int programID)
     {
            return ProgramDataMapper.GetProgram(programID);
     }
}

Наконец, производный класс:

public class DynamicProgram : Program
{
    // Additional Business Related Properties

    public new static DynamicProgram GetProgram(int programID)
        {
            return (DynamicProgram)Program.GetProgram(programID);
        }
}

Это компилируется просто отлично, но я получаю исключение Cannot приведение "Program" к "DynamicProgram" во время выполнения.

А как насчет универсального метода?Если я не ошибаюсь здесь, но теоретически мы не можем сделать что-то вроде:

public static IProgram GetProgram<T>(int programID) where T : IProgram
{
    IProgram program;
    Type returnType = typeof(T);
    if(returnType is StaticProgram)
    {
        program = new StaticProgram();
    }
    else if(returnType = DynamicProgram)
    {
        program = new DynamicProgram();
    }

    //if (T is StaticProgram)
        //{
        //  returnValue = new StaticProgram();
        //}
        //else if (T is DynamicProgram)
        //{
        //  returnValue = new DynamicProgram();
        //}

    // db operations
}

Конечно, приведенный выше код не работает.Я получаю "Данное выражение никогда не относится к типу предоставленного типа (StaticProgram)."

Ответы [ 4 ]

1 голос
/ 08 октября 2010

Как насчет этого:

public static class ProgramDataMapper
{
    // Change to a generic here to manufacture any class deriving from Program.
    public static T GetProgram<T>(int programID)
        where T : Program, new()
    {
        T p = new T();
        // database stuff
        p.Name = reader["Name"].ToString();
        ...
        return p;
    }
}

public abstract class Program
{
    // Properties

    // Manufacture a concrete class that derives from Program
    public new static T GetProgram<T>(int programID)
        where T : Program, new()
    {
        return ProgramDataMapper.GetProgram<T>(programID);
    }
}

public class DynamicProgram : Program
{
    // Additional Business Related Properties

    public new static DynamicProgram GetProgram(int programID)
    {
        // Specifically manufacture a DynamicProgram
        return Program.GetProgram<DynamicProgram>(programID);
    }
}

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

Ваш опубликованный код не будет приведен к DynamicProgram, потому что вы специально сконструировали объект Program в ProgramDataMapper. Хотя DynamicProgram "является" программой, обратное неверно. В приведенном мною коде с использованием обобщений создается DynamicProgram, а не просто программа. Использование дженериков также полностью исключает необходимость приведения в методе DynamicProgram.GetProgram.

0 голосов
/ 07 октября 2010

Необходимо выяснить, какой из ваших подходов не нарушает LSP (принцип подстановки Лискова). Поскольку вы сказали это сами, это две совершенно разные вещи, поэтому использование модели наследования здесь не сработает. Избыточный код может быть удален в третий класс, который будет представлен через статические методы, или у вас может быть ссылка на этот «вспомогательный» класс внутри каждого из ваших двух программных объектов.

0 голосов
/ 07 октября 2010

Как насчет наличия статического класса для всего вашего DataAccess?

0 голосов
/ 07 октября 2010

Я попытался создать класс "Program" в качестве базового класса и унаследовал классы StaticProgram и DynamicProgram, но преобразование с понижением не поддерживается, поэтому я не могу вернуть объект "Program" из класса доступа к данным и привести его к "StaticProgram "класс и т. Д.

Странно, потому что именно это должно работать:

public Program GetProgram(){
    if(someDataCoulumn.Equals("Static")) {
        return new StaticProgram(...);
    } else {
         return new DynamicProgram(...);
    }
}

public void Caller(){
    var p = GetProgram();
    var sp = p as StaticProgram;
    if(sp != null) {
       DoSomethingWithStaticProgram(sp);
    } else {
       var dp = p as DynamicProgram;
       if(dp != null){
           DoSomethingWithDynamicProgram(dp);
       } else {
           throw new SomeBusinessException("Program is neither Static not Dynamic, instead it's " + p.GetType().FullName);
       }
    }

}
...