VB中的多态性和继承模式 [英] Polymorphism and inheritance patterns in VB

查看:114
本文介绍了VB中的多态性和继承模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于多态性的分类Visual Basic和VBA支持,让我们面对它,是弱势的一面,并且内置的继承支持是不存在的。

这篇小文章是关于我最终成功使用的一些模式

某些类型的继承和多态,还有一些没有用过

好吧。


让我们从明显的事情开始,结果不能很好地工作:

1.使用接口类和Implements对于多态性:


乍一看,这似乎是一个不错的选择。毕竟,在像Java / B $ Java这样的语言中,大多数程序员使用的接口实现至少经常作为继承,并且比许多事物的继承更好。此外,使用

接口允许多态,而不会破坏类型安全性。唉,在VB中

的东西并不像它们最初出现时那么好。


事实证明,接口和工具有时在有限的情况下很有用/>
情况,但他们在VB中的工作方式使他们经常需要额外的努力来维持并使他们在许多情况下表现得无法预测。

所有,而不是简单地要求所有接口成员实现并通过接口像Java那样使它们可见,

VB要求你明确地创建一个实现每个

接口使用限定名称的方法。其中每一个都是一个单独的方法

,它可以有自己不同的实现(哦,这可能是一个纠结的网络),并使所有案例的行为相同(就像你想要大约100%的

时间一样,你必须从每个接口明确调用一个中心方法

实现这种情况。


现在,如果这还不够糟糕,你最好小心,不要在错误的顺序中混合早期的

绑定和后期绑定代码在同一个类上,因为

如果你将一个Object变量设置为一个接口类型的变量,那么

对象就像你分配之前的接口实例一样

它。换句话说,即使它现在位于一个Object变量中,你也不能访问对象的任何成员或属性,而不是通过它暴露出来的那些

它之前使用的最后一个接口 - 进入

对象变量。真是一团糟。

2.使用组合和委托来模拟继承:


因为你不能让一个类隐式继承并扩展另一个类,我想到的下一件事就是创建一个继承的东西。暴露

的类与包含父类的实例的方法相同,然后

转发对包含的父的调用。从任何不应该使用的方法

来覆盖父行为。


在实践中,这是一个非常麻烦的事。如果您使用接口,编译器

将告诉您何时更改父级需要更改

继承 class,但是上面讨论了所有接口的开销。

如果你使用后期绑定而没有接口,那么你没有麻烦,但是你还要b / b
没有编译器强制你在父母改变的时候更新继承类

,并且可能需要花费很多精力来追踪它们。作为最后一击,你不能继承和覆盖父母

类私有的东西。

接下来,对于一些经常运作良好的东西。


1.对多态性使用后期绑定:


而不是使用接口,你可以简单地允许代码通过将所有内容存储在一个简单的Object

变量中,以多态方式使用某些类的实例。


这种技术确实有一些值得注意的向下,但上方通常可以比它更好。最大的缺点是编译器不能确保

只能跟随特定接口的类传递给期望使用该接口的程序

。如果它中断,它将在运行时中断。

最大的好处是它根本不需要太多的代码开销。


如果您的代码中有一部分'真的要求大量的

类可以通过某些程序互换使用,这可能是一个好方法

去。为了减轻缺点,尝试确保用这个

方式编写的代码将传递可能传递的每个类的实例,并调用

在测试的早期可能会被称为一个。这样,如果你确实打破了某些东西,你就会在部署之前了解它。如果需要

,请将一些自动化测试作为保险,并在每次

部署之前运行它们。

2.使用倒置的集装箱船(我相信我的这样做的方式是

的版本装饰模式。


在这种模式中,你实现了一个类似于继承的东西/>
类始终充当接口层,其运行时行为是由b / b在运行时封装的类实例决定的。用

换句话说,你可以装饰。一个clsQuery类,它提供了一个clsInvoiceLineQuerySpec的

实例。 clsQuery提供了公共

可访问的接口,而clsInvoiceLineQuerySpec有方法签名

clsQuery了解为clsQuery实例提供特定数据

常量和过程使其能够在特定的环境中运行(例如,

a SQL字符串)。


请注意,在这种情况下,使用b可能有点实际。接口" for

用于定义一般

接口类可用的特定类。除了通过该界面之外,特定类可能永远不需要访问任何其他方式,因此没有歧义或包裹

调用担心。


3.实例为类:


在许多情况下,通过
$ b $定制对象的行为就足够了b单独初始化数据。在这种情况下,您可以使用公共函数

使用正确的数据初始化对象,然后返回它。通过为每个类提供一个

克隆过程,可以在此方案中实现

继承的形式,因此您可以克隆一个并将其行为扩展或修改为

处理一个更具体的案例。


例如,让我们说我有一个类clsQuery来获取它的所有行为

来自成员的值称为ParametersClause,SelectList,FromClause,

WhereClause,GroupByClause和HavingClause。现在,让我们假设您提供了一个名为InvoiceLineQuery的公共函数,该函数使用SelectList =" tblInvoiceLines。*初始化clsQuery实例

。和FromClause =" tblInvoices"。现在,

你有一个可以查询整个tblInvoiceLines表的对象。


现在,实现另一个名为InvoiceLinesForInvoice的函数调用

InvoiceLineQuery获取实例,然后设置ParametersClause =

" prmInvoiceId Long"和WhereClause =

" tblInvoiceLines.InvoiceId = prmInvoiceId"。这个实例可以用来查询

只是特定发票的行。


正如你所看到的,这可能是一种相当有用的实际继承。

请注意,.NET与WindowsForms模型类似。每个

WindowsForm对象都是在运行时构造的,但是构造的代码结构通过顺序添加
$ b来实现一种继承。 $ b项目到表格的集合。我相信这是装饰模式的另一种实现。

The classing Visual Basic and VBA support for polymorphism, let''s face it, is
a bit on the weak side, and built-in support for inheritance is non-existent.
This little essay is about some patterns I''ve ended up using successfully for
certain kinds of inheritance and polymorphism, and some that have not worked
out so well.

Let''s start with obvious things that turn out not to work well:
1. Use interface classes and "Implements" for polymorphism:

At first glance, this seems like a fine choice. After all, in languages like
Java, interface implementation is used by most programmers at least as often
as inheritance, and is better than inheritance for many things. Also, using
interfaces allows for polymorphism without breaking type safety. Alas, in VB
things are not as good as they at first appear.

As it turns out, interfaces and Implements are useful sometimes in limited
circumstances, but the way they work in VB makes them often take extra effort
to maintain and makes them behave unpredictably in many circumstances.
First of all, rather than simply requiring that all the interface members be
implemented and making them visible through the interface like Java would do,
VB requries you to explicitly create an implementation of each method for each
interface using a qualified name. Each of these is then a separate method
that can its own different implementation (oh what a tangled web that could
be), and to make all cases act the same (like you want about 100% of the
time), you must explicitly call one central method from each of the interface
implementations fo the case.

Now, if that weren''t bad enough, you''d best be careful never to mix early
binding and late binding code on the same classes in the wrong order because
if you set an Object variable equal to a variable of an interface type, the
object behaves as an instance of the interface it was in before you assigned
it. In other words, even though it is now housed in an Object variable, you
can''t access any members or attributes of the object other than the ones
exposed through the last interface it used as before it went -in- to the
Object variable. What a mess.
2. Using composition and delegation to simulate inheritance:

Since you can''t have one class implicitly inherit from and extend another, the
next thing that comes to mind is to create an "inheriting" class that exposes
the same methods as and contains an instance of the parent class, then
forwards calls to the contained "parent" from any method that is not supposed
to override the parent behavior.

In practice, this is a seious hassle. If you use interfaces, the compiler
will tell you when a change to the parent necessitates a change to the
"inheriting" class, but with all the overhead of interfaces discussed above.
If you use late binding and no interfaces, then you don''t have the hassle, but
you also don''t have the compiler forcing you to update the inheriting classes
when a parent changes, and it can be a lot of effort tracking them down. As a
final blow, you can''t inherit and override anything private to the "parent"
class.
Next, for some things that often do work well.

1. Using late binding for polymorphism:

Rather than using interfaces, you can simply allow code to use instances of
certain classes polymorhically by storing everything in a simple Object
variable.

This technique does have some notable down-sides, but the up-sides can often
outweigh it. The biggest down-side is that the compiler can''t make sure that
only classes that follow a particular interface can be passed to procedures
that expect to use that interface. If it breaks, it will break at run-time.
The big up-side is that it doesn''t require much code overhead at all.

If there''s a part of your code that''s really begging for a large number of
classes to be used interchangeably by some procedures, this may be a good way
to go. To mitigate the down-sides, try to make sure code that''s written this
way will pass instances of every class that might be passed, and call
everything that might be called one each one early in testing. That way, if
you do break something, you''ll know about it before you deploy it. If
necessary, write some automated tests as insurance, and run them before each
deployment.
2. Use inverted containership (I believe my way of doing this is a version of
the "Decorator Pattern").

In this pattern, you implement something resembling inheritance by having one
class that always acts as the interface layer, and its run-time behavior is
determined by what kind of class instance it is encapsulating at run-time. In
other words, you might "decorate" a clsQuery class by supplying it with an
instance of clsInvoiceLineQuerySpec. clsQuery provides the publicly
accessible interface, and clsInvoiceLineQuerySpec has method signatures
clsQuery understands that provide the clsQuery instance with specific data
constants and procedures that enable it to operate in a specific context (e.g.
a SQL string).

Note that in this case, it can be somewhat practical to use an "Interface" for
the specific classes to define what they must make available to the general
interface class. The specific classes might never need to be accessed any
other way than through that interface, so there are no ambiguities or wrapped
calls to worry about.

3. Instances as "classes":

In many cases, it is sufficient to customize the behavior of an object through
initialization data alone. In this case, you can have a public function that
initializes an object with the correct data, and returns it. A form of
inheritance can be implemented in this scheme by supplying each class with a
Clone procedure, so you can clone one and extend or modify its behavior to
handle a more specific case.

For instance, let''s say I have a class clsQuery that gets all its behavior
from the values of members called ParametersClause, SelectList, FromClause,
WhereClause, GroupByClause, and HavingClause. Now, let''s say you provide a
public function called InvoiceLineQuery that initializes a clsQuery instance
with SelectList = "tblInvoiceLines.*" and FromClause = "tblInvoices". Now,
you have an object that can query the entire tblInvoiceLines table.

Now, implement another function called InvoiceLinesForInvoice that calls
InvoiceLineQuery to get an instance, then sets ParametersClause =
"prmInvoiceId Long" and WhereClause =
"tblInvoiceLines.InvoiceId=prmInvoiceId". This instance can be used to query
just the lines for a particular invoice.

As you can see, this can be a reasonably useful sort of real inheritance.
Note that .NET does similar things with the WindowsForms model. Each
WindowsForm object is constructed at run-time, but the code structures that do
the construction allow for a sort of inheritance by sequential addition of
items to the form''s collections. I believe this is another sort of
implementation of the "Decorator Pattern".

推荐答案

不知怎的,我可以'似乎没有向Usenet发布任何内容而没有在发布后立即发现

明显的编辑错误。
Somehow, I can''t seem to post anything to Usenet without suddenly finding a
glaring editing mistake right after posting it.
分类Visual Basic和VBA支持多态,让我们面对它,有点偏弱,并且内置的继承支持是不存在的。
The classing Visual Basic and VBA support for polymorphism, let''s face it, is
a bit on the weak side, and built-in support for inheritance is non-existent.




应该阅读...


Visual Basic和VBA对类多态性的支持,让我们面对它,弱点是

位,并构建-in支持继承是不存在的。



That should read...

The Visual Basic and VBA support for class polymorphism, let''s face it, is a
bit on the weak side, and built-in support for inheritance is non-existent.


Steve Jorgensen写道:
Steve Jorgensen wrote:
2.使用倒置的集装箱船(我相信我这样做的方式是装饰模式的版本。)

在这种模式中,你实现了通过使一个
类始终充当接口层来实现类似继承的东西,并且它的运行时行为由它在运行时封装的类实例决定。换句话说,你可以装饰。一个clsQuery类,它为clsInvoiceLineQuerySpec提供了一个
实例。 clsQuery提供了公开的可访问接口,而clsInvoiceLineQuerySpec具有方法签名.clsQuery了解为clsQuery实例提供特定数据的常量和过程,使其能够在特定的上下文中运行(例如
一个SQL字符串)。

请注意,在这种情况下,使用接口可能在某种程度上是可行的。对于
特定类来定义它们必须提供给一般
接口类的内容。除了通过该界面之外,可能永远不需要访问特定的类,因此不会有任何含糊不清或需要担心的调用。
2. Use inverted containership (I believe my way of doing this is a version of
the "Decorator Pattern").

In this pattern, you implement something resembling inheritance by having one
class that always acts as the interface layer, and its run-time behavior is
determined by what kind of class instance it is encapsulating at run-time. In
other words, you might "decorate" a clsQuery class by supplying it with an
instance of clsInvoiceLineQuerySpec. clsQuery provides the publicly
accessible interface, and clsInvoiceLineQuerySpec has method signatures
clsQuery understands that provide the clsQuery instance with specific data
constants and procedures that enable it to operate in a specific context (e.g.
a SQL string).

Note that in this case, it can be somewhat practical to use an "Interface" for
the specific classes to define what they must make available to the general
interface class. The specific classes might never need to be accessed any
other way than through that interface, so there are no ambiguities or wrapped
calls to worry about.




实际上,你没有通过传递一个

另一个对象的实例来装饰一个对象。您通过将对象传递给装饰器对象的实例

来装饰对象。多态(通过接口)是模式的基本原则,因此您可以使用任意数量的其他对象顺序装饰初始对象

。当在最后一个装饰器上调用定义的方法

时,它们将首先在所有

中被称为包含的对象。


以这种方式构建查询可能很有趣,但是你只需要用所有必要的方法构建一个类的#3方式就可以使

更有意义。




Actually, you don''t decorate an object by passing it an instance of
another object. You decorate an object by passing it to an instance
of the decorator object. Polymorphism (via an interface) is fundamental
to the pattern so that you can sequentially decorate the initial object
with any number of additional objects. When the defined method(s) are
called on the last decorator they are called last in first out on all
the contained objects.

It might be entertaining to build a query that way, but your #3 way of
simply building a class with all the necessary methods probably makes
more sense.



2004年12月16日星期四02:12:53 GMT,rkc< rk *@rochester.yabba.dabba.do .rr.bomb>

写道:
On Thu, 16 Dec 2004 02:12:53 GMT, rkc <rk*@rochester.yabba.dabba.do.rr.bomb>
wrote:
Steve Jorgensen写道:

....
其实,你不要通过传递另一个对象的实例来装饰对象。您通过将对象传递给装饰器对象的实例来装饰对象。多态(通过接口)是模式的基础,因此您可以使用任意数量的其他对象顺序装饰初始对象。当在最后一个装饰器上调用定义的方法时,它们首先在所有包含的对象上被调用。


关于装饰模式,听起来我真的不明白。我会

尝试更清楚地了解这一点,并看看我是否可以弄清楚如果有任何现有的命名模式我的模式实际上类似于什么。

以这种方式构建查询可能很有趣,但是你只需用所有必要的方法构建一个类的#3方式可能会使
更有意义。
Steve Jorgensen wrote:
....
Actually, you don''t decorate an object by passing it an instance of
another object. You decorate an object by passing it to an instance
of the decorator object. Polymorphism (via an interface) is fundamental
to the pattern so that you can sequentially decorate the initial object
with any number of additional objects. When the defined method(s) are
called on the last decorator they are called last in first out on all
the contained objects.
Regarding the Decorator Pattern, it sounds like I really don''t get it. I''ll
try to get more clear on that and also see if I can figure out what if any
existing named pattern my pattern actually resembles.
It might be entertaining to build a query that way, but your #3 way of
simply building a class with all the necessary methods probably makes
more sense.




我同意。选项3是我通常用于查询类的,它的工作原理很好。我发现选项2与读者/作者类很好地合作,

但是对它的解释有点冗长。



I agree. Option 3 is what I normally use for query classes, and it works
really well. I have found option 2 to work well with reader/writer classes,
but the explanation of that is a bit lengthy.


这篇关于VB中的多态性和继承模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆