我怎样才能更好地设计它? (避免使用面向对象设计的switch语句)

时间:2011-04-25 13:43:34

标签: c# oop design-patterns

我对Object Oriented design了解一点,但我不确定如何在我的代码中使用这些原则。这就是我正在做的事情:

    public void Query(Agency agency, Citation queryCitation) {
        queryCitation.AgencyCode = agency.AgencyCode;

        switch (agency.ClientDb.Type) {
            case "SQL":
                QueryOracle(agency, queryCitation);
                break;
            case "PIC":
                QueryPick(agency, queryCitation);
                break;
        }
    }

(其中大部分是来自NHibernate的对象。我正在使用遗留数据库系统并将其部分重构为代码库。)显然,我可以在这里做一些不同的事情,这样我就不需要重复的功能了对于具有相同输入的不同数据库查询。它应该根据代理对象知道是使用Oracle数据库还是选择数据库连接。 (如果你从未听说过Pick数据库,那么直到我开始在这里工作之前我都没有。我们通过HTTP请求对它进行查询,所以它不是SQL。)

我应该创建一个接口,例如名为“ClientDbConnection”,然后创建两个实现该接口的类,移动代码以查询数据库,然后使用“agency.clientDb.Query(queryCitation)”替换这整个功能?我想我在这里大声思考,但对此的任何意见都将不胜感激。

6 个答案:

答案 0 :(得分:12)

代理商是您控制的一个类吗?如果是这样的话:

public abstract class GenericDb
{
    public abstract void Query(parms);
}

在您的代理机构类中,您可以

public GenericDb ClientDb {get; set;}

然后有一个SqlDb类,如:

public class SqlDb : GenericDb
{
    public void Query(parms);
}

public class PicDb : GenericDb
{
    public void Query(parms);
}

然后这段代码:

public void Query(Agency agency, Citation queryCitation) {
        queryCitation.AgencyCode = agency.AgencyCode;

        switch (agency.ClientDb.Type) {
            case "SQL":
                QueryOracle(agency, queryCitation);
                break;
            case "PIC":
                QueryPick(agency, queryCitation);
                break;
        }
    }

变为

public void Query(Agency agency, Citation queryCitation) {
        queryCitation.AgencyCode = agency.AgencyCode;
        agency.ClientDb.Query(queryCitation);
    }

由于继承,它将知道ClientDb具有GenericDb的基类。它将通过ClientDb参数的类型知道它是应该运行SqlDb还是PicDb或Oracle等。

答案 1 :(得分:5)

您可能希望在此处实施策略模式。基本上,switch语句中的每个可能的“类型”都将成为它自己的一个实现相同接口的类。

Applying the Strategy Pattern

然后,您可以使用以“type”值作为参数的工厂方法。该方法将返回正确的类(其返回类型是上面提到的接口)。

答案 2 :(得分:3)

我会重构利用界面。我可能会这样做:

public interface IQuery
{
    void Execute(Agency agency, Citation query);
}

public class OracleQuery : IQuery
{
    // Implementation
}

public class PickQuery : IQuery
{
    // Implementation
}

然后,您可以更改Agency类以存储IQuery对象的实例,而不是(或除了)ClientDb对象之外:

public class Agency
{
    public IQuery Query { get; set; }
}

然后在初始化代码中(通常设置ClientDb属性),可以将实例设置为适当的IQuery实现:

agency.Query = new PickQuery();

答案 3 :(得分:2)

ADO.NET有一组通用类:DbCommand,DbConnection等......它们还实现了另一组通用接口:IDbCommand,IDbConnection等......

所以你可以使用它们,但它最终可能会变得非常复杂。您的解决方案的优势在于它非常易读。另外,pick数据库可能没有任何ADO.NET提供程序......

PS:我会替换Type属性类型,而是使用枚举。

答案 4 :(得分:2)

要编写更少的代码但提高可读性,可以使用每个数据库的委托切换到字典的声明代码级别。这很容易扩展,并且非常易读。考虑到更多功能性方法,您可以获得类似

的内容
void Query(Agency agency, Citation queryCitation)
{
    Dictionary<string, Action<Agency, Citation>> QueryMap = new Dictionary<string, Action<Agency, Citation>>
    {
        { "SQL", QueryOracle},
        { "PIC", QueryPic}
    };


    queryCitation.AgencyCode = agency.AgencyCode;

    QueryMap[agency.ClientDb.Type](agency, queryCitation);
}

答案 5 :(得分:0)

有两个OOP解决方案polymorphism Visitor pattern