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

发布于 2024-11-02 23:21:23 字数 904 浏览 1 评论 0原文

我对面向对象设计了解一点,但我不确定如何使用我的代码中的这些原则。这是我正在做的事情:(

    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 数据库连接。 (如果您从未听说过 Pick 数据库,那么在我开始在这里工作之前我也没有听说过。我们通过 HTTP 请求对其进行查询,因此它不是 SQL。)

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

I know a little bit about Object Oriented design, but I'm not sure how to go about using those principles in my code. Here's what I'm working on:

    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;
        }
    }

(Most of these are objects from NHibernate. I'm working with a legacy database system and am refactoring parts of it into a code library.) Clearly, I could do something differently here so that I don't need duplicate functions for different database queries that have the same input. It should just know based off of the agency object whether to use an Oracle database or a Pick database connection. (If you've never heard of a Pick database, well I hadn't either until I started working here. We make queries to it through HTTP requests, so it's not SQL.)

Should I make an interface, for example called "ClientDbConnection" and then make two classes that implement that interface, move the code to query the database to those and then have something like "agency.clientDb.Query(queryCitation)" replace this whole function? I guess I'm thinking aloud here, but any input on this would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

葬シ愛 2024-11-09 23:21:23

Agency 是你控制的类吗?如果是这样,请执行以下操作:

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

在您的 Agency 类中,您可以有

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等。

Is Agency a class you control? If so do something like this:

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

In your Agency Class, you could have

public GenericDb ClientDb {get; set;}

Then have a SqlDb class like:

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

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

Then this code:

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;
        }
    }

becomes

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

Because of inheritance, it will know that ClientDb has a base class of GenericDb. It will know by the type of the ClientDb parameter whether it should run the SqlDb or the PicDb or Oracle etc.

一绘本一梦想 2024-11-09 23:21:23

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

应用策略模式

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

You will likely want to implement the strategy pattern here. Basically, each of your possible "types" in your switch statement would become a class of its own that implements the same interface.

Applying the Strategy Pattern

You can then use a factory method that takes a "type" value as its parameter. That method would return the correct class (its return type is the interface mentioned above).

仙气飘飘 2024-11-09 23:21:23

我会重构以利用接口。我可能会这样做:

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();

I would refactor to take advantage of an interface. I would probably make it something like:

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

public class OracleQuery : IQuery
{
    // Implementation
}

public class PickQuery : IQuery
{
    // Implementation
}

You could then change the Agency class to store an instance of an IQuery object rather than (or in addition to) the ClientDb object:

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

And then in your initialization code (where you would normally set the ClientDb property), you could set the instance to the appropriate IQuery implementation:

agency.Query = new PickQuery();
深海里的那抹蓝 2024-11-09 23:21:23

要编写更少的代码但提高声明性代码级别的可读性,您可以切换到带有每个数据库委托的字典。它可以很容易地扩展并且非常可读。考虑到更实用的方法,你会得到类似的东西

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);
}

To write less code but improve readability the the level of declaritive code you can swith to a dictionary with delegates for each database. That can easily be extended and is very readable. With that more functional approach in mind you get something like

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);
}
末蓝 2024-11-09 23:21:23

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

因此您可以使用它们,但最终可能会变得相当复杂。您的解决方案的优点是它非常具有可读性。另外,也许选择数据库没有任何 ADO.NET 提供程序...

PS:不过,我会替换 Type 属性类型,并使用枚举代替。

ADO.NET has a set of generic classes: DbCommand, DbConnection, etc... that also implement another set of generic interfaces: IDbCommand, IDbConnection, etc...

So you could use them, but it may become quite complicated in the end. The advantage of your solution is it's very readable. Plus maybe the pick database does not have any ADO.NET provider...

PS: I would replace the Type property type though, and use an enum instead.

青衫负雪 2024-11-09 23:21:23

有两种OOP解决方案多态性访客模式

There are two OOP solutions polymorphism and Visitor pattern.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文