パッケージとサブパッケージとprotected
パッケージ分けた時に、パッケージ間には2種類の関係があるような。
xxx.yyy.zzz.util | ユーティリティパッケージ |
xxx.yyy.zzz.util.date | 日付関連のユーティリティパッケージ |
xxx.yyy.zzz.util.string | 文字列関連のユーティリティパッケージ |
xxx.yyy.zzz.print | 印刷パッケージ |
xxx.yyy.zzz.print.excel | Excel関連の印刷パッケージ |
xxx.yyy.zzz.print.pdf | PDF関連の印刷パッケージ |
というパッケージがあれば、utilとprintは初期に見出され、util.*とprint.*は分析/設計が進む上で登場する感じ。
util.*は、utilのクラス群を分類しているだけ。
print.*は、printに印刷に関する抽象クラス群を配置して、print.excelにはexcelの実装、print.pdfにはPDFの実装を配置している(これも分類と言えば分類だけど…)。
例えば、printがutilに依存していたとしても、(継承は別として)protecedなスコープで参照することはなく、あくまでインターフェースあるいはpublicなスコープで参照する。
ところがprintとprint.*については、printに抽象化されているクラス群があり、print.excelとprint.pdfからはパッケージとして”継承関係”みたいな関係に見える。そのため、クラスとしては継承していないが、protecedな参照をしたい場合があったりする。
パッケージの「横の関係」と「縦の関係」というのがあるような気がしてならない。
Interfaceとprotected
パッケージ内で継承関係にないクラスでも、インターフェースを介してアクセスする場合で「publicじゃないんだけどなぁ」という場合があった。
その時は、クラスに求められる「publicな振る舞い」と「protectedな振る舞い」は、そもそも役割が違うってことで”異なるインターフェース”として定義するべきだ、と解釈してみた。
多分「publicな振る舞い」は設計/分析レベルで見出すメソッド、「protectedな振る舞い」は実装に近い設計レベルで見出したメソッドという感じがしてる。
そんな自分と同じような疑問を持った方の質問とその議論。
@IT > interface のメソッドは、なぜ protected にできないのでしょうか?
@IT > class or interface ?
試してみたところ、アクセスレベルを指定しないInterfaceだと、少なくともパッケージ内でのみのインターフェースという形で定義できる。
interface NoSpecifiedInterface { void noSpecifiedProcess(); }
だったら、protetedと指定できてもいいんじゃね?と思ってみたりw
インナーインターフェース?
インナークラスがあるんだったら、インナーインターフェースもできるかな?と思ったら、やっぱできるんだ。
package jp.saku.test; public class TestAccessLevel { public TestAccessLevel() { super(); } public void proccess() { NoSpecifiedInterface noSpecifiedClass = createNoSpecified(); noSpecifiedClass.noSpecifiedProcess(); PrivateInterface privateClass = createPrivate(); privateClass.privateProcess(); ProctectedInterface proctectedClass = createProtected(); proctectedClass.protectedProcess(); PublicInterface publicClass = createPublic(); publicClass.publicProcess(); } public NoSpecifiedInterface createNoSpecified() { return new NoSpecifiedClass(); } public PrivateInterface createPrivate() { return new PrivateClass(); } public ProctectedInterface createProtected() { return new ProctectedClass(); } public PublicInterface createPublic() { return new PublicClass(); } class NoSpecifiedClass implements NoSpecifiedInterface { public NoSpecifiedClass() { super(); } public void noSpecifiedProcess() { } } private class PrivateClass implements PrivateInterface { public PrivateClass() { super(); } public void privateProcess() { } } protected class ProctectedClass implements ProctectedInterface { public ProctectedClass() { super(); } public void protectedProcess() { } } public class PublicClass implements PublicInterface { public PublicClass() { super(); } public void publicProcess() { } } interface NoSpecifiedInterface { public void noSpecifiedProcess(); } private interface PrivateInterface { public void privateProcess(); } protected interface ProctectedInterface { public void protectedProcess(); } public interface PublicInterface { public void publicProcess(); } }
このTestAccessLevelを継承したクラスからの参照だと
package jp.saku.test; // import文が不要 public class TestAccessLevelExtend extends TestAccessLevel { public TestAccessLevelExtend() { super(); } public void proccess() { NoSpecifiedInterface noSpecifiedClass = createNoSpecified(); noSpecifiedClass.noSpecifiedProcess(); // PrivateInterfaceが参照できない //PrivateInterface privateClass = new TestAccessLevelOtherPackage().createPrivate(); //privateClass.privateProcess(); ProctectedInterface proctectedClass = createProtected(); proctectedClass.protectedProcess(); PublicInterface publicClass = createPublic(); publicClass.publicProcess(); } }
このTestAccessLevelと同じパッケージのクラスからの参照だと、
package jp.saku.test; import jp.saku.test.TestAccessLevel.NoSpecifiedInterface; import jp.saku.test.TestAccessLevel.ProctectedInterface; import jp.saku.test.TestAccessLevel.PublicInterface; public class TestAccessLevelRef { public TestAccessLevelRef() { super(); } public void proccess() { NoSpecifiedInterface noSpecifiedClass = new TestAccessLevel().createNoSpecified(); noSpecifiedClass.noSpecifiedProcess(); // PrivateInterfaceが参照できない //PrivateInterface privateClass = new TestAccessLevelOtherPackage().createPrivate(); //privateClass.privateProcess(); ProctectedInterface proctectedClass = new TestAccessLevel().createProtected(); proctectedClass.protectedProcess(); PublicInterface publicClass = new TestAccessLevel().createPublic(); publicClass.publicProcess(); } }
このTestAccessLevelと別のパッケージのクラスからの参照だと、
package jp.saku.test.test; import jp.saku.test.TestAccessLevel; import jp.saku.test.TestAccessLevel.PublicInterface; public class TestAccessLevelOtherPackage { public TestAccessLevelOtherPackage() { super(); } public void proccess() { // NoSpecifiedInterfaceが参照できない //NoSpecifiedInterface noSpecifiedClass = new TestAccessLevel().createNoSpecified(); //noSpecifiedClass.noSpecifiedProcess(); // PrivateInterfaceが参照できない //PrivateInterface privateClass = new TestAccessLevelOtherPackage().createPrivate(); //privateClass.privateProcess(); // ProctectedInterfaceが参照できない //ProctectedInterface proctectedClass = new TestAccessLevel().createProtected(); //proctectedClass.protectedProcess(); PublicInterface publicClass = new TestAccessLevel().createPublic(); publicClass.publicProcess(); } }