Redian新闻
>
interesting "protect" behavior
avatar
interesting "protect" behavior# Java - 爪哇娇娃
c*t
1
A post a few days ago mentioned if a parent could access child's
function. I thought that it might be interesting to write a
post on "protect".
Any intro Java programmer will know that, given parent class A,
its child classes can access A's protected functions. People
rarely have to think the other way around:
what about A accessing its child class protected functions?
Turn out that you can in Java, and occasionally it can be useful.
The main advantage is that sometimes it can be used
avatar
g*g
2
It looks like a dirty trick in a glance. If the parent needs
to access the child, maybe the child should not be the child
in the first place. A typical example is CallBack like ActionListener,

【在 c*****t 的大作中提到】
: A post a few days ago mentioned if a parent could access child's
: function. I thought that it might be interesting to write a
: post on "protect".
: Any intro Java programmer will know that, given parent class A,
: its child classes can access A's protected functions. People
: rarely have to think the other way around:
: what about A accessing its child class protected functions?
: Turn out that you can in Java, and occasionally it can be useful.
: The main advantage is that sometimes it can be used

avatar
h*0
3
说实话,这个看起来不像java,像C++。
比如那个B m_this = (B)this,当你创建一个A的对象时,这种转换难道不会挂掉吗?

【在 c*****t 的大作中提到】
: A post a few days ago mentioned if a parent could access child's
: function. I thought that it might be interesting to write a
: post on "protect".
: Any intro Java programmer will know that, given parent class A,
: its child classes can access A's protected functions. People
: rarely have to think the other way around:
: what about A accessing its child class protected functions?
: Turn out that you can in Java, and occasionally it can be useful.
: The main advantage is that sometimes it can be used

avatar
c*t
4
There are several down sides using Listeners, which makes it very
difficult to use.
1. You were writing a listener interface that is used only once.
Interface isn't meant to be used this way.
2. The implementation is simply wrapping function call.
3. Very tedious (as the number of functions needs to be done can
be a lot). In compiler-compiler case, there are usually dozens
of functions to be dealt this way.
4. Difficult to change a function. You need to refactor twice to
change a f

【在 g*****g 的大作中提到】
: It looks like a dirty trick in a glance. If the parent needs
: to access the child, maybe the child should not be the child
: in the first place. A typical example is CallBack like ActionListener,

avatar
c*t
5

Personally, I dislike code without prefixes for private variables. I
oftentimes read code without IDE (like browsing in CVS/SVN). It can be
confusing (since parameter names can shadow the instance variable names).
Also, have a prefix is good thing to know for sure that you are dealing
with a variable/function when dealing with reflection based code.
Of course it won't. You just need to make A abstract or the constructor
protected. Further, you can make A a package scope class without limiti

【在 h*****0 的大作中提到】
: 说实话,这个看起来不像java,像C++。
: 比如那个B m_this = (B)this,当你创建一个A的对象时,这种转换难道不会挂掉吗?

avatar
h*0
6
第一个问题是各有所爱啦。
我觉得第二个问题,是违反了面向对象原则的。你的A类,就只能且必须有B类这一个子
类。如果再有其它任何A的子类,马上就挂掉。在这种情况下,基本上A,B就是一个类
。写成两个类,并加上各种奇怪的东西,感觉不合适。

【在 c*****t 的大作中提到】
:
: Personally, I dislike code without prefixes for private variables. I
: oftentimes read code without IDE (like browsing in CVS/SVN). It can be
: confusing (since parameter names can shadow the instance variable names).
: Also, have a prefix is good thing to know for sure that you are dealing
: with a variable/function when dealing with reflection based code.
: Of course it won't. You just need to make A abstract or the constructor
: protected. Further, you can make A a package scope class without limiti

avatar
h*0
7
另外,我说像C++,是因为你提到了B只有能A一个父类……java里肯定只有一个父类,
再加若干接口。
总之如果没有标准支持,你的做法应该属于“undefined behavior”,说不定换个版本
的编译器就不让通过了或者换个版本的虚拟机就运行出错了?

【在 c*****t 的大作中提到】
:
: Personally, I dislike code without prefixes for private variables. I
: oftentimes read code without IDE (like browsing in CVS/SVN). It can be
: confusing (since parameter names can shadow the instance variable names).
: Also, have a prefix is good thing to know for sure that you are dealing
: with a variable/function when dealing with reflection based code.
: Of course it won't. You just need to make A abstract or the constructor
: protected. Further, you can make A a package scope class without limiti

avatar
g*g
8
Interface is not necessary if you don't need that level of
separation. You can pass B in A's constructor, and in the
constructor, you call B's setA to make A visible for B.
The only limit is you have to use either public or default
and put them in the same package.
Now if you seriously think about inheritance, then why not
just use inner class. You can declare one as public static inner
class of another.
I don't see how your trick is simpler than this.
avatar
c*t
9
The issue with inner class is:
How in the world do you generate class A and insert into class B
without introducing some major headaches? Vice versa. Modifying
user's code by code generator is not a good idea since many possible
error conditions could wipe out user's code.
Remember a while back that I had a post on generating a pseudo
inner class in a separate file? It was for this purpose. It doesn't
work well.
Regarding passing A. It is another good solution, but calling A's
functions fro

【在 g*****g 的大作中提到】
: Interface is not necessary if you don't need that level of
: separation. You can pass B in A's constructor, and in the
: constructor, you call B's setA to make A visible for B.
: The only limit is you have to use either public or default
: and put them in the same package.
: Now if you seriously think about inheritance, then why not
: just use inner class. You can declare one as public static inner
: class of another.
: I don't see how your trick is simpler than this.

avatar
c*t
10
Actually I did more research on this protect. I was wrong in saying
A can call B. Actually, because protect has less restriction than
default (protect = default + nonpackage scope child class access).
So the real reason why parent could access the child was because parent
and child are in the same package. Thus, it is well defined.

【在 h*****0 的大作中提到】
: 另外,我说像C++,是因为你提到了B只有能A一个父类……java里肯定只有一个父类,
: 再加若干接口。
: 总之如果没有标准支持,你的做法应该属于“undefined behavior”,说不定换个版本
: 的编译器就不让通过了或者换个版本的虚拟机就运行出错了?

avatar
F*n
11
Why putting A and B in same package and use package scope limiting the
location of B's classes?

【在 c*****t 的大作中提到】
: A post a few days ago mentioned if a parent could access child's
: function. I thought that it might be interesting to write a
: post on "protect".
: Any intro Java programmer will know that, given parent class A,
: its child classes can access A's protected functions. People
: rarely have to think the other way around:
: what about A accessing its child class protected functions?
: Turn out that you can in Java, and occasionally it can be useful.
: The main advantage is that sometimes it can be used

avatar
m*t
12
How is this different from what the Template pattern does in a less,
err, unorthodox way? :-)
I.e.:
class A {
protected void incLineNumber() {
// default impl.
// If a subclass must provide an implementation but A cannot be
// made abstract, throw an exception here.
}
}
class B extends A {
@Override
protected void incLineNumber() {
// B's impl
}
}

【在 c*****t 的大作中提到】
: A post a few days ago mentioned if a parent could access child's
: function. I thought that it might be interesting to write a
: post on "protect".
: Any intro Java programmer will know that, given parent class A,
: its child classes can access A's protected functions. People
: rarely have to think the other way around:
: what about A accessing its child class protected functions?
: Turn out that you can in Java, and occasionally it can be useful.
: The main advantage is that sometimes it can be used

avatar
s*e
13
The trick is a clear example of misunderstanding OOD.
In java class design, I do not think that you ever want to break the
following two simple rules.
1. Concern should be separate among classes.
2. The parent should never assume anything about a child. If it does need,
which means that assumption may well belong to the parent as somebody
pointed out with "template" pattern.
avatar
c*t
14
I think you underestimated how many times parent has to know
what the child is. Just think about why reflection is such
a necessary and useful tool for Java.

【在 s******e 的大作中提到】
: The trick is a clear example of misunderstanding OOD.
: In java class design, I do not think that you ever want to break the
: following two simple rules.
: 1. Concern should be separate among classes.
: 2. The parent should never assume anything about a child. If it does need,
: which means that assumption may well belong to the parent as somebody
: pointed out with "template" pattern.

avatar
h*0
15
reflection不能太大量使用吧?

【在 c*****t 的大作中提到】
: I think you underestimated how many times parent has to know
: what the child is. Just think about why reflection is such
: a necessary and useful tool for Java.

avatar
c*t
16
Generating a corresponding function in A is actually harder than what
you would think, because B as child could add/remove/modify the functions,
return signature, and scope without doing refactoring. This would
generate a compilation error, and thus prevent my tool (which requires
B to be free of errors) from regenerating A. This is a chicken-and-egg
problem, which happens a lot in the prototyping phase where things get
worked out little by little. Tried this before, didn't work well since
mu

【在 m******t 的大作中提到】
: How is this different from what the Template pattern does in a less,
: err, unorthodox way? :-)
: I.e.:
: class A {
: protected void incLineNumber() {
: // default impl.
: // If a subclass must provide an implementation but A cannot be
: // made abstract, throw an exception here.
: }
: }

avatar
m*t
17
You know, now I think you are just talking about these tricky situations as
a shameless plug for your CookCC. ;-)
Seriously though, I understand B is not under your control, but I don't
understand how, once you have fixed a callback method in A, B could change
it. Perhaps some example would help.

【在 c*****t 的大作中提到】
: Generating a corresponding function in A is actually harder than what
: you would think, because B as child could add/remove/modify the functions,
: return signature, and scope without doing refactoring. This would
: generate a compilation error, and thus prevent my tool (which requires
: B to be free of errors) from regenerating A. This is a chicken-and-egg
: problem, which happens a lot in the prototyping phase where things get
: worked out little by little. Tried this before, didn't work well since
: mu

avatar
m*t
18

So I went back and looked at your original example. B doesn't have to
extend A, I don't think. How about A taking an interface, say,
LineNumberIncreaser, which essentially provides a callback hook for
whatever line number increasing logic your user wishes to implement?
Even if B has to extend A, I don't understand how B could change the
incLineNumber() template defined in A... or why there is any good reason
for your user to do so.

【在 m******t 的大作中提到】
: You know, now I think you are just talking about these tricky situations as
: a shameless plug for your CookCC. ;-)
: Seriously though, I understand B is not under your control, but I don't
: understand how, once you have fixed a callback method in A, B could change
: it. Perhaps some example would help.

avatar
g*g
19
He doesn't like the observer pattern, saying having to change
3 files blah blah.
I still think that's a dirty trick, good practices do not need
to do it that way. But I can understand once a while a shortcut
is fine.

【在 m******t 的大作中提到】
:
: So I went back and looked at your original example. B doesn't have to
: extend A, I don't think. How about A taking an interface, say,
: LineNumberIncreaser, which essentially provides a callback hook for
: whatever line number increasing logic your user wishes to implement?
: Even if B has to extend A, I don't understand how B could change the
: incLineNumber() template defined in A... or why there is any good reason
: for your user to do so.

avatar
s*e
20
Please elaborate why reflection is naturally related to "parent-child
relationship".
In real life, parents do know their children. But in OOP/OOD, the parent
class just provides some "gene", convinience, or skeleton (template) for
child class to use. If you want to assume sth for child, why can't you put
that stuff in the parent.

【在 c*****t 的大作中提到】
: I think you underestimated how many times parent has to know
: what the child is. Just think about why reflection is such
: a necessary and useful tool for Java.

avatar
c*t
21
There are two cases I know of
1. Return parameter cannot be specified at parent. For example,
class ComponentSampleModel; //parent
class ByteComponentSampleModel extends ComponentSampleModel
{
public byte[] getData ();
}
class ShortComponentSampleModel extends ComponentSampleModel
{
public short[] getData ();
}
// also int version
Parent knows exactly what the possible children are (byte, short, int),
can code algorithms in one place (rather than repeated 3 times) at
parent le

【在 s******e 的大作中提到】
: Please elaborate why reflection is naturally related to "parent-child
: relationship".
: In real life, parents do know their children. But in OOP/OOD, the parent
: class just provides some "gene", convinience, or skeleton (template) for
: child class to use. If you want to assume sth for child, why can't you put
: that stuff in the parent.

avatar
m*t
22
I once had to design an api similar to the first case. There was some
debate with myself that the real OO way would be to uniformly return
Number[], however the pragmatic me won with the performance argument.
avatar
F*n
23
The "standard" solution is to use
Object getData()
Since you are using primitive array and reflection you have to cast it anyway.This way you don't need reflection.

【在 m******t 的大作中提到】
: I once had to design an api similar to the first case. There was some
: debate with myself that the real OO way would be to uniformly return
: Number[], however the pragmatic me won with the performance argument.

avatar
F*n
24
Actually what you describe does not sound like parent-child relationship in
conventional OOP. It is more like the multi-perspective problems addressed
by Aspect-oriented programming, as they point out sometimes there are needs
of multiple abstraction and OO hierarchies.
For example, in the main abstraction A is parent of B, but in another
abstraction B many be parent of A. Java cannot handle this. In C++ you can
tweak it with "friend" access. AOP is more structured handling of this. What
your de

【在 c*****t 的大作中提到】
: There are two cases I know of
: 1. Return parameter cannot be specified at parent. For example,
: class ComponentSampleModel; //parent
: class ByteComponentSampleModel extends ComponentSampleModel
: {
: public byte[] getData ();
: }
: class ShortComponentSampleModel extends ComponentSampleModel
: {
: public short[] getData ();

相关阅读
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。