3

请看下面的代码:

    Public Class A
    Public person1 As Person
End Class

Public Class B
    Inherits A

    Public Function CheckGender() As Boolean
        If person1._Gender = "M" Then
            CheckGender = True
        End If
    End Function

End Class

Public Class C
    Inherits B
    Public Function CheckAge() As Boolean
        If person1._Age > 30 Then
            CheckAge = True
        End If
    End Function

End Class

Public Class D
    Inherits C

    Public Sub SomeMethod()
        Dim list As List(Of Person) = New List(Of Person)
        Dim p1 As New Person("Ian", "M", 31)
        Dim p2 As New Person("Susan", "F", 20)
        Dim p3 As New Person("Mark", "M", 22)
        list.Add(p1)
        list.Add(p2)
        list.Add(p3)

        For Each Person As Person In list
            person1 = Person
            If CheckAge() And CheckGender() Then
                'Do something
            End If
        Next
    End Sub

    Public Shared Sub Main()
        Dim d As New D
        d.SomeMethod()
    End Sub

End Class

Public Class Person
    Public _Name As String
    Public _Gender As String
    Public _Age As String
    Public Sub New(ByVal Name As String, ByVal Gender As String, ByVal Age As Integer)
        _Name = Name
        _Gender = Gender
        _Age = Age
    End Sub
End Class

c.SomeMethod遍历三个人并进行两次检查:b.CheckGenderc.CheckAgeCheckGenderCheckAge使用超类中的实例变量A

实时环境中的代码每天循环访问数据库中的 100,000 条记录,并删除那些CheckGender同时CheckAge为 true 的记录。 在这种情况下使用实例变量是一个糟糕的设计选择吗? 我总是被教导使用局部变量。我希望该对象被Person传递给每个循环。还是真的不重要?CheckGenderCheckAge

请注意,上面的代码是一个假设的例子。 CheckGender是实际应用中CheckAge的复杂功能。

4

2 回答 2

2

只要CheckGenderCheckAge不访问层次结构中类的任何私有、受保护或内部成员,并且是公共函数,并且它们的逻辑对于任何实例都是相同的,存在ABC,将这些方法包含在中是一个更好的设计另一个班级。如果可能,使它们成为静态的。您可以让他们接受您的类的最通用实现(A例如),允许检查年龄或性别。从您的代码中获取,您甚至可以传递Person属性而不是使用任何A,BC类。

在上述情况下使用继承和这种逻辑是允许的,只要您需要执行以下任何或所有操作:

  • 符合特定的接口或基类,即ABC必须实现/扩展,并且该接口或基类提供CheckGenderCheckAge方法。如果您将对象传递给第三方 API,这可能是唯一的解决方案,该 API 接受基类/接口作为参数并在内部调用检查方法。

这是 C# 中的示例:

public static class CheckUtil
{
    public static bool CheckAgeOfPerson(Person p)
    {
        return p.Age > 30;
    }
    public static bool CheckAgeOfObject(A obj)
    {
        // NOTE: obj.person1 must be accessible - by being either public or internal.
        // If this class is in another assembly, internal is not useful
        return CheckAgeOfPerson(obj.person1);
    }
}

A objA = ...;
B objB = ...;
C objC = ...;

CheckUtil.CheckAgeOfObject(objA);
CheckUtil.CheckAgeOfObject(objB);
CheckUtil.CheckAgeOfObject(objC);

CheckUtil.CheckAgeOfPerson(objA.person1);
CheckUtil.CheckAgeOfPerson(objB.person1);
CheckUtil.CheckAgeOfPerson(objC.person1);
  • 为类提供特定的实现。如果您必须对 的实例进行一些逻辑CheckAgeA但对 的实例进行完全不同的验证B,或者将现有的逻辑和一些新的逻辑结合起来C,那么继承就是您的朋友。尽管如此,如果是这种情况,我更愿意将CheckGenderand暴露CheckAge给接口并通过接口调用它们。这样,只要满足接口,继承是有效的,但不是强制性的。

这是 C# 中的一个示例:

public interface IGenderCheckable
{
    bool CheckGender();
}

public interface IAgeCheckable
{
    bool CheckAge();
}

public class A : IAgeCheckable, IGenderCheckable
{
    public virtual bool CheckGender()
    {
        return this.person1.Gender.Equals("M");
    }

    public virtual bool CheckAge()
    {
        return this.person1.Age > 30;
    }
}

public class B : A
{
     public override bool CheckAge()
     {
          // combine custom logic with new logic
          return this.person1.Age < 0 || base.CheckAge();
     }
}

对于复杂的场景,也可以使用两种方法的组合(当然对于比年龄和性别检查更复杂的情况):

public class A : IAgeCheckable, IGenderCheckable
{
    ...
}

public static class CheckUtil
{
    public static bool CheckAge(IAgeCheckable obj)
    {
        return obj.CheckAge();
    }
    public static bool CheckGender(IGenderCheckable)
    {
        return obj.CheckGender();
    }
}

关于实例变量与局部变量的使用 - 在 .NET 中使用实例变量的性能存在缺陷,尤其是当它们是值类型时。例如,本地成员的使用int _someIntMember被转换为this._someIntMember- 这反过来又调用堆来获取this对象,然后访问其_someIntMember成员。将成员作为局部变量,将其值放入堆栈,然后从那里读取它,而无需通过堆进行不必要的往返。而且,栈比堆快。

但是,我不能说过多的堆使用是否是对它的滥用,也不是在使用过多时滥用局部变量。这取决于所需的性能和代码的复杂性。有时局部变量会使代码更具可读性,但如果太多,您很容易忘记每个变量是什么(这可能比疏忽的性能提升更严重)。所以这是一个风格和必要性的问题。

于 2013-04-03T19:44:37.533 回答
2

如果您有兴趣“修复”您的代码以使 Person 成为属性而不是字段,请更改 A 类的实现,如下所示:

Public Class A
    Public Property Person1 As Person

   Public Overridable Function ComputeAge() As Integer
       Return Person1.Age
   End Function

End Class

这样做的好处是,如果需要,您可以添加额外的抽象来获取和设置此属性。编译器将为 auto 属性生成一个隐藏的私有支持字段。您仍然可以从任何实现类访问 Person1:

Public Class B
   Inherits A

   Public Overrides Function ComputeAge() As Integer
       Return MyBase.Person1.Age.AddYears(1)
   End Function
End Class
于 2013-04-03T21:03:11.163 回答