锁定老帖子 主题:访问者模式的进阶
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (4)
|
|
---|---|
作者 | 正文 |
发表时间:2009-07-24
能这么想不错!不过我担心接口类会很多,而且把本应放一起的方法拆分开了
|
|
返回顶楼 | |
发表时间:2009-07-24
my 2 cents:
Vistor interface should be the top interface in the whole category of visitors, such as ManVisitor, WomanVisitor. One reason is that the accept(Visitor visitor) method is the top one and the consequence of this fact. The classic approach, namely, having all visit(...) methods in one class, works better for me, with a little twist and a condition. The little twist is that we implement a default, no action class for the interface. For example, interface PersonVisitor { visit(Man man); visit(Woman woman); } class DefaultVisitor implements PersonVisitor { visit(Man man) {} visit(Woman woman) {} } Then your Love, Success, Fail classes all inherent from the above. Adding new behaviors for Person is easy, just add a new class, no change to the existing class. Adding new Person classes is also simpler, say we want to add Elf class: class Elf implements Person { ... } Now we just change the top classes: interface PersonVisitor { visit(Man man); visit(Woman woman); visit(Elf elf); } class DefaultVisitor implements PersonVisitor { visit(Man man) {} visit(Woman woman) {} visit(Elf elf) {} } There is no need to change the existing visitor classes, they just take the default no-op action from the above class. We have the option to overwrite this as well(in this case, we have to change the existing class, but this is unavoidable in any approach). This freedom is very important in my practice, sometimes we want to overwrite it, sometime we don't, the judgement is made on the base case by case. The reflection based approach doesn't work for finer granularity, e.g., if I have 300K objects to visit, the reflection is painfully slow(I do have a case like this, not my imagination, in fact, I don't have that kind of imagination, too much to bear). The approach you presented here is called acyclic visitor, the call to "instanceof" is also slow if we have a lot of objects). So I would think these two approaches work well in a context where there are less visitable objects, such as framework implementation. The condition that I mentioned above is the inherence hirarchy of the visitable classes, without care, the double reflection can go wrong siliently because it goes to the proper method based on the parameter class(we give it a Man object, it goes to visit(Man); we give it a Woman object, it goes to visit(Woman)). So every time when we add a new visitable object, we need to make the class hirarchy is in good state. Several examples I've worked: In math, we have matrices, there are a lot of different matrices, such as diagonal, triangle, sparse, etc. There are also operations on them, addition, subtraction, etc. These math operations are quick tricky, for example, addition. Adding two general matrices results a general matrix, this operation is quite expensive if the size of the matrix is huge. However, adding two diagonal matrices are much simpler, adding one diagonal matrix to an upper triangle matrix is also simple. So we want to handle these special cases separately. Another example is in finance. We have trades/transactions, they handle what we buy/sell, when, etc... Inside the trade, we have financial instrument/security or product which we buy/sell; inside the product, we have the issuer who issue the product. For example, a buy trade on a GE bond. The transaction can have many different implementations, more complicated than just buy/sell. The product can be a bond, equity, derivative, etc. The issuer can be government, corp, em, etc. So we have 3 levels of visitors to handle the specifics. We could have millions of active trades to maintain everyday. We need to evalute the current positions, the risk, etc. Visitor pattern is a very powerful pattern, it removes a lot of if-else blocks. I've seen cases where there are more than 10 if-else embedded, this kind of cases is very hard to maintain without this pattern. |
|
返回顶楼 | |