请查看以下代码:
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.CheckGender
和c.CheckAge
。 CheckGender
和CheckAge
使用超类A
中的实例变量。
实时环境中的代码每天在数据库中循环100,000条记录,并删除CheckGender
和CheckAge
都为真的记录。 在这种情况下使用实例变量是一个糟糕的设计选择吗?我总是被教导使用局部变量。我希望Person
对象在每个循环中传递给CheckGender
和CheckAge
。或者它真的没关系?
请注意,上述代码是一个假设的例子。 CheckGender
和CheckAge
是实际应用程序中的复杂函数。
答案 0 :(得分:2)
只要CheckGender
和CheckAge
没有访问层次结构中类的任何私有,受保护或内部成员,并且是公共函数,并且它们的逻辑对于任何实例都是相同的,那么{ {1}},A
或B
,将这些方法放在另一个类中是更好的设计。尽可能使它们静止。您可以让他们接受您的类的最一般实现(例如C
),允许检查年龄或性别。从您的代码中获取,您甚至可以传递A
属性,而不是使用任何Person
,A
和B
类。
在上述情况下使用继承并允许这样的逻辑,只要您需要执行以下任何或所有操作:
C
,A
和B
类必须实现/扩展,以及该接口或基类提供C
和CheckGender
方法。如果您将对象传递给第三方API,这可以是唯一的解决方案,它接受基类/接口作为参数并在内部调用检查方法。以下是C#中的示例:
CheckAge
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);
的实例需要CheckAge
中的某些逻辑,但对A
的实例进行完全不同的验证,或B
中现有逻辑和某些新逻辑的组合然后继承是你的朋友。不过,如果是这种情况,我宁愿将C
和CheckGender
暴露给接口并通过接口调用它们。这样,只要接口满足,继承就是有效的,但不是强制性的。这是C#中的一个例子:
CheckAge
对于复杂的情景,也可以使用两种方法的组合(当然,对于比年龄和性别检查更复杂的情况):
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();
}
}
关于实例变量与局部变量的使用 - 在.NET中使用实例变量的性能存在缺陷,特别是当它们是值类型时。例如,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();
}
}
的本地成员的使用被转换为int _someIntMember
- 后者又调用堆来获取this._someIntMember
对象,然后访问其this
成员。将该成员作为局部变量,将其值放入堆栈中,并从那里读取它,而不必通过堆进行不必要的往返。而且,堆栈比堆快。
但是,我不能说过多的堆使用是滥用它,也不能说当它们被过多使用时滥用局部变量。这取决于所需的性能和代码的复杂性。有时局部变量会使代码更具可读性,但如果太多,您可能很容易忘记每个代码是什么(这可能是比疏忽性能增益更严重的问题)。所以这是一个风格和必要性问题。
答案 1 :(得分:2)
如果您有兴趣“修复”您的代码以使Person成为Property而不是字段,请按如下方式更改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