Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 很多没有函数性的派生类只是为了“知道”它们的类型_C#_.net_Oop_Design Patterns - Fatal编程技术网

C# 很多没有函数性的派生类只是为了“知道”它们的类型

C# 很多没有函数性的派生类只是为了“知道”它们的类型,c#,.net,oop,design-patterns,C#,.net,Oop,Design Patterns,我认为下面的问题有更好的解决办法 假设我们有以下的类结构: class Foo { public int Id { get; set; } } class Bar1 : Foo { } class Bar2 : Foo { } class Bar3 : Foo { } //.. A lot more of these Foo derivations 派生类没有任何功能。 以下示例说明了这些类的用途: 从Foo对象列表中Id为5的Bar3类型的特定类型对象访问特定对象。 在G

我认为下面的问题有更好的解决办法

假设我们有以下的类结构:

class Foo
{
    public int Id { get; set; }
}

class Bar1 : Foo
{

}

class Bar2 : Foo
{

}

class Bar3 : Foo
{

}
//.. A lot more of these Foo derivations
派生类没有任何功能。 以下示例说明了这些类的用途:

从Foo对象列表中Id为5的Bar3类型的特定类型对象访问特定对象。 在GUI中显示与类型Foo中的特定对象相关的不同数据。 有没有更好的方法来识别这些对象中的一个而不衍生它们


谢谢

最好改用枚举

class Foo
{
    public int Id { get; set; }

    public FooKind Kind { get; set; }
}

子类应该增强父类的功能。

最好改用枚举

class Foo
{
    public int Id { get; set; }

    public FooKind Kind { get; set; }
}
子类应该增强父类的功能。

如果它们在语义上相同并且对派生类没有意义,则可以创建枚举:

并将属性添加到Foo:

现在您可以:

过滤器:

foos.Where(x => x.SomeGreatEnum == SomeGreatEnum.Bar1);
基于枚举类型绑定到GUI

如果它们在语义上相同并且对派生词没有意义,则可以创建枚举:

并将属性添加到Foo:

现在您可以:

过滤器:

foos.Where(x => x.SomeGreatEnum == SomeGreatEnum.Bar1);
基于枚举类型绑定到GUI


我认为这感觉像个问题的原因是代码的其他部分不是非常面向对象的

让我解释一下。假设您使用enum选项。然后,每当您想要对一个Foo执行某些操作时(这对于每种Foo都是不同的),您都需要使用switch语句,或者通过一些其他方法(如枚举示例中的.Where调用)选择集合中的部分项。随着代码的发展,您将有太多这样的语句,它将开始感觉错误。针对一个Foo的每一个不同操作,都需要处理各种Foo。此外,每当您对代码的这些部分进行更改时,您都必须确保正确地将它们分开,这意味着您需要立即了解所有类型的Foo行为背后的逻辑

如果逻辑有可能变得更复杂,我建议使用接口和多类方法而不是枚举方法


现在,在您的代码中,您可能正在管理Foos之外的行为差异。为了使它更面向对象,您可能希望让Foo自己管理这种差异。

我认为这感觉像是一个问题的原因是您的代码中还有其他部分不是非常面向对象的

让我解释一下。假设您使用enum选项。然后,每当您想要对一个Foo执行某些操作时(这对于每种Foo都是不同的),您都需要使用switch语句,或者通过一些其他方法(如枚举示例中的.Where调用)选择集合中的部分项。随着代码的发展,您将有太多这样的语句,它将开始感觉错误。针对一个Foo的每一个不同操作,都需要处理各种Foo。此外,每当您对代码的这些部分进行更改时,您都必须确保正确地将它们分开,这意味着您需要立即了解所有类型的Foo行为背后的逻辑

如果逻辑有可能变得更复杂,我建议使用接口和多类方法而不是枚举方法


现在,在您的代码中,您可能正在管理Foos之外的行为差异。为了使其更加面向对象,您希望让FOO自己管理这种差异。

您可以使用访问者模式:

    class Visitor
    {
        public void Visit(Bar1 foo)
        {
            Console.WriteLine("Bar1 ID:" + foo.Id);
        }

        public void Visit(Bar2 foo)
        {
            Console.WriteLine("Bar2 ID:" + foo.Id);
        }

        public void Visit(Bar3 foo)
        {
            Console.WriteLine("Bar3 ID:" + foo.Id);
        }
    }
我稍微修改了你的课程:

    abstract class Foo
    {
        public int Id { get; set; }

        public abstract void Accept(Visitor visitor);
    }

    class Bar1 : Foo
    {
        public override void Accept(Visitor visitor)
        {
            visitor.Visit(this);
        }
    }

    class Bar2 : Foo
    {
        public override void Accept(Visitor visitor)
        {
            visitor.Visit(this);
        }
    }

    class Bar3 : Foo
    {
        public override void Accept(Visitor visitor)
        {
            visitor.Visit(this);
        }
    }
现在,让一切顺利进行:

        var visitor = new Visitor();
        var lst = new List<Foo> 
            { 
                new Bar1() { Id = 1 }, 
                new Bar2() { Id = 2 }, 
                new Bar3() { Id = 3 } 
            };
        foreach(var element in lst) 
        {
            element.Accept(visitor);
        }

        /* Output is:
         *
         * Bar1 ID:1
         * Bar2 ID:2
         * Bar3 ID:3
         */
完整的设计模式要求访问者实现一个接口,该接口将用于Accept方法的签名

您可以找到有关Visitor设计模式的更多信息以及.Net framework中使用的Visitor设计模式示例

使用此设计模式的主要缺点是它在访问者和被访问的具体元素之间创建了耦合


例如,当添加一个新类Bar4:Foo时,它需要覆盖Accept方法,并且访问者还需要使用新的访问方法重载进行更新。

您可以使用访问者模式:

    class Visitor
    {
        public void Visit(Bar1 foo)
        {
            Console.WriteLine("Bar1 ID:" + foo.Id);
        }

        public void Visit(Bar2 foo)
        {
            Console.WriteLine("Bar2 ID:" + foo.Id);
        }

        public void Visit(Bar3 foo)
        {
            Console.WriteLine("Bar3 ID:" + foo.Id);
        }
    }
我稍微修改了你的课程:

    abstract class Foo
    {
        public int Id { get; set; }

        public abstract void Accept(Visitor visitor);
    }

    class Bar1 : Foo
    {
        public override void Accept(Visitor visitor)
        {
            visitor.Visit(this);
        }
    }

    class Bar2 : Foo
    {
        public override void Accept(Visitor visitor)
        {
            visitor.Visit(this);
        }
    }

    class Bar3 : Foo
    {
        public override void Accept(Visitor visitor)
        {
            visitor.Visit(this);
        }
    }
现在,让一切顺利进行:

        var visitor = new Visitor();
        var lst = new List<Foo> 
            { 
                new Bar1() { Id = 1 }, 
                new Bar2() { Id = 2 }, 
                new Bar3() { Id = 3 } 
            };
        foreach(var element in lst) 
        {
            element.Accept(visitor);
        }

        /* Output is:
         *
         * Bar1 ID:1
         * Bar2 ID:2
         * Bar3 ID:3
         */
完整的设计模式要求访问者实现一个接口,该接口将用于Accept方法的签名

您可以找到有关Visitor设计模式的更多信息以及.Net framework中使用的Visitor设计模式示例

使用此设计模式的主要缺点是它在访问者和被访问的具体元素之间创建了耦合

例如,当添加一个新类Bar4:Foo时,它将需要重写Accept方法,并且访问者也将
eed将使用新的访问方法重载进行更新。

您可以使用空接口,即所谓的标记或属性,用于相同的目的。这两个问题听起来像是UI问题,而不是实体建模问题。根据UI框架的不同,您可以有多个视图和视图模型,其中只包含需要显示的数据字段。搜索单独的类型取决于您如何确定类型。它可能是一个枚举字段或查询的结果。您可以使用空接口(称为标记或属性)用于相同的目的。这两个问题听起来像是UI问题,而不是实体建模问题。根据UI框架的不同,您可以有多个视图和视图模型,其中只包含需要显示的数据字段。搜索单独的类型取决于您如何确定类型。它可能是一个枚举字段或一个查询的结果。如果它们在语义上不相同呢?假设Bar1是一个实体,用户X有do句柄,而Bar2由用户Y处理。两个用户如何处理每个实体?它们会做不同的事情吗?这两个不同的实体是工作流中的任务,可以由不同的用户处理,并且如上所述,应该在GUI中显示不同的数据。@Stofa您完全可以根据枚举值对其进行不同的处理。这样可以节省为每个类型创建空类型的时间。如果它们在语义上不相同呢?假设Bar1是一个实体,用户X有do句柄,而Bar2由用户Y处理。两个用户如何处理每个实体?它们会做不同的事情吗?这两个不同的实体是工作流中的任务,可以由不同的用户处理,并且如上所述,应该在GUI中显示不同的数据。@Stofa您完全可以根据枚举值对其进行不同的处理。这将节省您为每个类型创建空类型的时间。谢谢你的回答。你是对的,这也是我问这个问题的原因。我的问题是,那些条对象是实体,我真的不想在Domainlayer中实现所有与它们相关的东西。。。所以我试图找到一个更好的方法。也许我必须在问题中解释这一点。我的猜测是,如果您需要在GUI中以不同的方式对待它们,它们已经在域层中了。不是吗?也许你应该明确他们的存在。这并不一定意味着复制实体,域对象可以不同。这一切都归结为一个问题:是试图避免代码的复杂性,还是避免对领域中已经存在的复杂性进行编码?根据我的经验,从长远来看,后者总会导致难看的代码。谢谢你的回答。你是对的,这也是我问这个问题的原因。我的问题是,那些条对象是实体,我真的不想在Domainlayer中实现所有与它们相关的东西。。。所以我试图找到一个更好的方法。也许我必须在问题中解释这一点。我的猜测是,如果您需要在GUI中以不同的方式对待它们,它们已经在域层中了。不是吗?也许你应该明确他们的存在。这并不一定意味着复制实体,域对象可以不同。这一切都归结为一个问题:是试图避免代码的复杂性,还是避免对领域中已经存在的复杂性进行编码?根据我的经验,从长远来看,后者总是会导致难看的代码。