アクセス修飾子 クラスとインスタンスで扱いは同じ?

アクセス修飾子はクラス間のアクセスを制御する仕組みだす。
しかし、クラスとインスタンスを同じに考えてクラスに対する制限がそのままインスタンスに適用されると理解していると思わぬ失敗をしてしまいます。クラスはクラス、インスタンスはインスタンスなのです。

まず、UML図で違いを見てみましょう。
下図のようにスーパークラスを継承しているサブクラスのインスタンスを作るって考えてみます。

インスタンスの作成

図に示すようChild01のインスタンスにはChild01がParent01を継承しているので、Parent01の持っているgetmsg群のメソッドとChild01が持っているgetChildmsg群のメソッドがあります。
Parent01の持っているアクセス修飾子なしのgetmsg3メソッドはサブクラスのChild01からはアクセスできない事はアクセス修飾子 それぞれの違いで説明しましたから、Main01Child01はgetmsg3メソッド以外のインスタンスに含まれるメソッドはアクセスできると考えても仕方がないかもしれません。

しかし、実際のアクセスは下図のような結果になります。

アクセス可能範囲

まず、同じパッケージに属するChild01が持つgetChildmsg群のメソッドは全てMain01Child01からアクセス出来ます。しかし、Child01のスーパークラスParent01が持つメソッドについては、アクセス修飾子なしのgetmsg3メソッドがアクセス出来ないのは明らかとしても、サブクラスからアクセスできるはずのprotected指定されたgetmsg2メソッドもアクセスできません。これはアクセスがサブクラスからではなくサブクラスのインスタンスからだからです。
インスタンスは元になったクラスがサブクラスの場合、サブクラスとそのスーパークラスの仕様・特徴(フィールとメソッド)を持ちますが、スーパークラスのメソッドが持っているアクセス修飾子protectedの意味が変わるわけではありません。
そこで、アクセス修飾子がpublicの時以外は個々にメソッドの所有者に指定されたアクセス修飾子の影響範囲を判断する必要があります。

それでは、具体的なコードで確認しましょう。
まず、スーパークラスのParent01.javaです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package ex01.parent;
 
public class Parent01 {
 
    public void getmsg1() {
        System.out.println("親クラスでもpublicなメソッドはどこからでも呼べる");
    }
    protected void getmsg2(String msg) {
        System.out.println(msg);
    }
    void getmsg3(String msg1, String msg2) {
        System.out.println(msg1 + msg2);
    }
}

サブクラスのChild01.javaです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package ex01;
import ex01.parent.Parent01;
 
public class Child01 extends Parent01 {
    public Child01() {
        super.getmsg1();
        super.getmsg2("別パッケージ内の親クラスのprotectedメソッドは子クラスから呼べる");
//      super.getmsg3("別パッケージ内の親クラスのアクセス修飾子なしのメソッドは", "子クラスから呼べばない");
    }
     
    public void getChildmsg1() {
        System.out.println("インスタンス内のpublicなメソッドはどこからでも呼べる");
    }
    protected void getChildmsg2(String msg) {
        System.out.println(msg);
    }
    void getChildmsg3(String msg1, String msg2) {
        System.out.println(msg1 + msg2);
    }
 
}

ここで、8行目の別パッケージ内の親クラスのアクセス修飾子なしのメソッドgetmsg3の呼び出しはアクセス修飾子 それぞれの違いで確認したようにコンパイルエラーになるのでコメントアウトしています。

Child01のインスタンスを作り、実行するMain01Child01.javaです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package ex01;
 
public class Main01Child01 {
    public static void main(String args[]) {
        Child01 cd = new Child01();
         
        System.out.println("---------- インスタンスからのアクセス ----------");
        cd.getmsg1();
        cd.getmsg2("別パッケージ内の親クラスのprotectedメソッドは子クラスのインスタンスから呼べない");
        cd.getmsg3("別パッケージ内の親クラスのアクセス修飾子なしのメソッドは", "子クラスのインスタンスから呼べばない");
         
        cd.getChildmsg1();
        cd.getChildmsg2("子クラスの持つprotectedメソッドは子クラスのインスタンスから呼べる");
        cd.getChildmsg3("子クラスの持つアクセス修飾子なしのメソッドは", "子クラスのインスタンスから呼べる");
    }
}

Main01Child01.javaをコンパイルすると、

C:\javaCode>javac ex01\Main01Child01.java
ex01\Main01Child01.java:9: エラー: getmsg2(String)はParent01でprotectedアクセス されます
                cd.getmsg2("別パッケージ内の親クラスのprotectedメソッドは子クラ スのインスタンスから呼べない");
                  ^
ex01\Main01Child01.java:10: エラー: シンボルを見つけられません
                cd.getmsg3("別パッケージ内の親クラスのアクセス修飾子なしのメソッドは", "子クラスのインスタンスから呼べばない");
                  ^
  シンボル:   メソッド getmsg3(String,String)
  場所: タイプChild01の変数 cd
エラー2個
 
C:\javaCode>

となり、別パッケージ内の親クラスのprotected及びアクセス修飾子なしのメソッドは子クラスのインスタンスから呼べない事が分かります。特にprotected指定のメソッドについてはクラスからと、インスタンスからとではアクセス修飾子の影響が変わったように見えるので注意が必要です。

そこで、9行目と10行目をコメントアウトしてコンパイルし、実行すると、

C:\javaCode>java ex01.Main01Child01
親クラスでもpublicなメソッドはどこからでも呼べる
別パッケージ内の親クラスのprotectedメソッドは子クラスから呼べる
---------- インスタンスからのアクセス ----------
親クラスでもpublicなメソッドはどこからでも呼べる
インスタンス内のpublicなメソッドはどこからでも呼べる
子クラスの持つprotectedメソッドは子クラスのインスタンスから呼べる
子クラスの持つアクセス修飾子なしのメソッドは子クラスのインスタンスから呼べる
 
C:\javaCode>

となり、前半UML図で確認したインスタンスからアクセスする場合にアクセス可能なメソッドが明確になります。

カテゴリー: Java | タグ: , , , | アクセス修飾子 クラスとインスタンスで扱いは同じ? はコメントを受け付けていません

アクセス修飾子 それぞれの違い

Javaのアクセス修飾子には最もアクセス制限の緩いpublicから制限の厳しいprivateまで、以下の4種類があります。

修飾子 UMLの可視性 説明
public + すべてのクラスからアクセス可能
protected # 同じパックージ内のクラス、もしくはパッケージ外のサブクラスからアクセス可能
指定なし(デフォルト) ~ 同じパックージ内のクラスからのみアクセス可能
private 同一クラス内からのみアクセス可能

クラス宣言に使えるアクセス修飾子は、publicと指定なしの2種類です。privateはインナークラスの宣言時に限って利用できます。
フィールドやメソッドは、4種類とも指定可能です。

それでは、parentパッケージにpublic指定したParentクラスを作り、そのクラスにpublic、protected、指定なしの3種類の指定をしたメソッドを作り、それらメソッドをパッケージ外に作るChildクラスから呼んでアクセス制限がどのようにかかるか見てみましょう。
まず、parentパッケージにスパークラス(親クラス)としてParent.javaを作り、オーバーロードしたメソッドを三つ作って、それぞれに異なるアクセス修飾子を指定します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package parent;
 
public class Parent {
        private String msg;
        public void setmsg(String msg) {
                this.msg = msg;
        }
        public void getmsg() {
                System.out.println(msg);
        }
        protected void getmsg(String msg) {
                System.out.println(msg);
        }
        void getmsg(String nashi, String msg) {
                System.out.println(msg);
        }
}

次にparentパケージ外にParentのサブクラス(子クラス)として作るChild.java

1
2
3
4
5
6
7
8
9
10
import parent.Parent;
 
public class Child extends Parent {
        public Child() {
                super.setmsg("子から親のpublicメソッドは呼べる");
                super.getmsg();
                super.getmsg("子から親のprotectedメソッドも呼べる");
                super.getmsg("アクセス修飾子なし", "子から親のアクセス修飾子なしメソッドは呼べない");
        }
}


Childクラスをコンパイルすると、以下のようにChild.javaの8行目、親クラスの「アクセス修飾子なし」のメソッドを呼んでいる所で「メソッドにアクセス出来ない」というコンパイルエラーが出ます。

C:\work\java>javac Child.java
Child.java:8: エラー: Parentのgetmsg(String,String)はpublicではありません。パッ ケージ外からはアクセスできません
                super.getmsg("アクセス修飾子なし", "子から親のアクセス修飾子なしメソッドは呼べない");
                     ^
エラー1個
 
C:\work\java>

つまり、アクセス修飾子なし指定の親クラスのメソッドはパケージ外の子クラスからはアクセスできません
一方、Child.javaの8行目をコメントアウトして再度コンパイルすると、エラーは出ずクラスファイルが出来るので、Childクラスのインスタンスを作るメインクラスChild_Main.javaを作り、実行します。
するとpublic及びprotectedを指定したメソッドはパケージ外の子クラスからでもアクセスできることが分かります。

1
2
3
4
5
public class Child_Main {
    public static void main(String args[]) {
        Child cd = new Child();
    }
}
C:\work\java>java Child_Main
子から親のpublicメソッドは呼べる
子から親のprotectedメソッドも呼べる
 
C:\work\java>

それでは、最後にアクセス修飾なし指定でアクセス可能な場合を調べてみましょう。
アクセス修飾なし指定されたメソッドは同じパッケージ内の別クラスからはアクセスできるはずなので、Parent.Javaと同じparentパケージ内にParent_Main.javaを作り、実行してみます。

1
2
3
4
5
6
7
8
9
10
11
package parent;
 
public class Parent_Main {
    public static void main(String args[]) {
        Parent cd = new Parent();
        cd.setmsg("同じパケージのpublicメソッドは呼べる");
        cd.getmsg();
        cd.getmsg("同じパケージのprotectedメソッドは親子関係がなくても呼べる");
        cd.getmsg("アクセス修飾子なし", "同じパケージのアクセス修飾子なしメソッドは呼べる");
    }
}
C:\work\java>java parent.Parent_Main
同じパケージのpublicメソッドは呼べる
同じパケージのprotectedメソッドは親子関係がなくても呼べる
同じパケージのアクセス修飾子なしメソッドは呼べる
 
C:\work\java>

このように、4つのアクセス修飾子のうち、区別が付きにくいのはprotectedと指定なしの違いです。
整理しておくと、protectedなフィールドやメソッドは、パッケージ外のサブクラスからでもアクセスできるのに対し、
アクセス修飾子を指定しなかった場合は、パッケージ外のサブクラスからはアクセスできず、同一パケージ内のクラスからのみアクセスできます。

カテゴリー: Java | タグ: , , , , | アクセス修飾子 それぞれの違い はコメントを受け付けていません

マークダウン記法を試す

講師研修の仕事も会社によって、使うツールが少しづつ違う。
それが、また ため になる。
今年4月からの研修ではEclipseをJSP、サーブレットの作成でフルに使いましたが、お蔭でだいぶEclipseが好きになりました。
そして、今準備している仕事ではレポートがマークダウン記法になる。
なんじゃ、MarkDown記法って?

簡単に言えば簡易HTML記法。特定のルールに従ってテキストを入力すれば特定のサイト(WordPressではJP Markdownをプラグインすれば良い)やメッセージツールでは自動的にHTML、CSSで修飾されたようなページになる。

たとえば

# ヘッダー h1
## ヘッダー h2
### ヘッダー h3

こう書けば、

ヘッダー h1

ヘッダー h2

ヘッダー h3

こうなるし、

こう書けば

***

こうなる


文中の 強調文字
半角スペースと**の並びとその逆並びで強調文字を囲うだけ、つまり

文中の **強調文字** は

こんなのも

```
ここには
プログラムコードを
貼り付ける
```

こうなるから面白い。

1
2
3
ここには
プログラムコードを
貼り付ける

そしてこれは

`これはマークダウン記法です。`

こうなる。
これはマークダウン記法です。

カテゴリー: WP 機能 | タグ: , | コメントする

ログイン処理(Daoを使った改良版)

前回のデータベースを使ったユーザ管理:ログイン処理(書き下し版)のプログラム構造を改良し、保守性、拡張性を向上させましょう。

まず、前回のプログラム構造を振り返ってみましょう。
ログイン処理(書き下し版)は四つのユースケース:ユーザ情報の一覧、ログインチェック、ユーザの追加、ユーザの削除をJSPとServletが個々に担当し、それぞれがデーターベースにアクセスして機能を実現していました。従って、

<ログイン処理(書き下し版)のプログラム構造的な問題>

  1. JSPは全体のUIを担当しているユーザ情報の一覧機能だけであるため、他のユースケースを担当するServletは処理の結果をユーザ情報の一覧機能に返して表示するしかなく、独自に自由な画面設計が出来ません。
  2. Javaプロググラム処理(ビジネスロジック・レイヤ)とデータベース処理(データベース・レイヤ)の切り分けが行われておらず、レイヤ間が密結合の状態で、データーベースの種類が変わったり、データの保存先がデータベースではなくファイルシステムに変わるような場合、全てのプログラムに変更が必要になり修正に手間がかかるだけでなく、修正時のミス防止やテストケースの増加などが予想されます。

1.はUIはJSP、コントロールはServletと役割を明確にしてプログラムを構成すれば改善できますが、2.の改善にはビジネスロジック・レイヤとデータベース・レイヤのレイヤごとの役割を明確化し、レイヤ間を疎結合にする必要があります。

そもそもオブジェクト指向プログラミング(Javaで作るビジネスロジック)とリレーショナルデータベース(データの永続化機構)との間には概念や構造の違いから発生するギャップ:インピーダンスミスマッチがあるといわれています。リレーショナルデータベースにアクセスするためのJDBCはJavaから直接呼び出すことが出来るのに「ギャップがある」というのは分かりにくいかもしれません。
これは例えばショッピングカートを考えた場合、ビジネスロジック側はショッピングカートをユーザごとにモデル化したオブジェクトとして扱うでしょうが、データベース側は正規化した複数のテーブルとテーブル間のリレーションで扱うため、両者の異なるデータ形式の変換が必ず必要になるという事です。

そこで、インピーダンスミスマッチの対応策の一つとしてJavaの開発元であったサン・マイクロシステムズがベスト・プラクティス・ガイドラインで提案したのがDAO:Data Access Objectです。
これはデータの永続化機構(例えばデータベース)とビジネスロジック間にDAOを位置付け、データベースに対するアクセスインターフェースを用意して、全てのデータアクセスをこのインターフェースを通して行わせ、データベースから取得した結果はDTO:Data Transfer Objectに格納する事により、永続化機構をビジネスロジックから隠蔽します。

ビジネスロジックに対するDAOを使ったデータ永続化機構隠蔽の概念図

DAOを使ったデータ永続化機構隠蔽
DAOとDTOを使ったユーザ管理処理の構成をクラス関連図にまとめました。

DaoとDtoを使ったユーザ管理のクラス関連図

この構成ではUIをJSP、コントロールをServletが担当するように事前に決めたので、いろいろな条件による画面の切り替えが容易になっていますし、Daoによりコントロールからデータベースアクセスが切り離されたのでコントロールの中が見やすくなっています。

まず、一連の操作を見てみましょう。
画像をクリックすると拡大画像が表示されます。
1. 初期画面

ログイン処理(Daoを使った改良版)01

選択できる4っの機能が表示されています。
2. 登録済みユーザの一覧

ログイン処理(Daoを使った改良版)02

初期画面でを選択すると表示されます。
3. ユーザログイン

ログイン処理(Daoを使った改良版)03

初期画面でを選択し、IDにあああ、パスワードに222と入力します。
4. 入力内容のチェック

ログイン処理(Daoを使った改良版)04

入力されたユーザ情報を登録されている情報と比較した結果、該当するユーザが見つからなかったので、再入力を促します。
5. 再ログイン

ログイン処理(Daoを使った改良版)05

今度はIDにあああ、パスワードに111と入力します。
6. ログイン成功

ログイン処理(Daoを使った改良版)06

入力されたユーザ情報と同じユーザ情報が登録されていたので、ログインを許可しメッセージを表示します。
7. 新規ユーザの登録

ログイン処理(Daoを使った改良版)07

初期画面でを選択し、IDにあああ、パスワードに111と入力します。
8. ユーザ情報の確認

ログイン処理(Daoを使った改良版)08

入力されたユーザ情報が登録されているユーザ情報と一致したため、既登録のユーザと判断し再入力を促します。
9. ユーザ情報の再入力

ログイン処理(Daoを使った改良版)09

今度はIDに山下、パスワードに555と入力します。
10. ユーザ登録成功

ログイン処理(Daoを使った改良版)09

入力されたユーザ情報と一致する既存ユーザ情報が発見されなかったので、新規のユーザ登録を許可し、メッセージを表示。
11. ユーザ一覧の再表示

ログイン処理(Daoを使った改良版)09

初期画面でを選択し、現在のユーザ一覧を表示します。
12. ユーザの削除

ログイン処理(Daoを使った改良版)09

初期画面でを選択し、削除するユーザのidをああああ、パスワードを111と入力します。
13. ユーザ情報確認

ログイン処理(Daoを使った改良版)09

入力されたユーザ情報と一致するユーザ情報が見つからなかったため、削除該当ユーザ無しとしてメッセージを表示し、再入力を促します。
14. ユーザ情報の再入力

ログイン処理(Daoを使った改良版)09

今度はユーザのidをあああ、パスワードを111と入力します。
15. ユーザ削除成功

ログイン処理(Daoを使った改良版)09

入力されたユーザ情報が既に登録済だったので、当該ユーザの情報を削除し、メッセージを表示。
16. 登録済みユーザの再表示

ログイン処理(Daoを使った改良版)09

初期画面でを選択し、現在の登録済みユーザ情報を確認します。
それでは、次に各処理のソースコードを見てみましょう。
特定のソースコードのみ確認したい場合は以下のボタンをクリックしてください。
登録済みユーザ一覧処理
ユーザログイン処理
ユーザ登録処理
ユーザ削除処理
DAOとDTO
まず、ユーザ管理処理のメインメニュー:login_main.jspです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ユーザ管理UI</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/login.css">
</head>
<body>
<h1>登録済みユーザ一覧</h1>
<form action="./UserListServlet" method="post">
    <button type="submit"><pre><big>登録済みユーザ一覧</big></pre></button>
</form>
<hr>
<h1>ユーザログイン</h1>
<form action="./user_login.jsp" method="post">
    <button type="submit"><pre><big>ログイン</big></pre></button>
</form>
<hr>
<h1>ユーザ登録</h1>
<form action="./user_regist.jsp" method="post">
    <button type="submit"><pre><big>ユーザ登録</big></pre></button>
</form>
<hr>
<h1>ユーザ削除</h1>
<form action="./user_delete.jsp" method="post">
    <button type="submit"><pre><big>ユーザ削除</big></pre></button>
</form>
<hr>
</body>
</html>

各機能ごとに専用のUIを読んでいるので、構造はシンプルです。
登録済みユーザ一覧については専用のUIによる入力が不要なので、直接コントロールのサーブレット:UserListServletを呼んでいます。

次は登録済みユーザ一覧のコントロールを行うサーブレット:UserListServlet.javaです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.example;
 
import java.io.IOException;
import java.util.ArrayList;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 * Servlet implementation class UserListServlet
 */
@WebServlet("/UserListServlet")
public class UserListServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
 
    /**
     * @see HttpServlet#HttpServlet()
     */
    public UserListServlet() {
        super();
    }
 
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
 
    UserDao dao = new UserDao();
    ArrayList<UserDto> list = dao.getUserList();
    request.setAttribute("list", list);
    request.getRequestDispatcher("user_list.jsp").forward(request, response);
    }
 
}

実際の処理はマーキングした部分でDAOのgetUserListメソッドで得たユーザ一覧情報をrequestオブジェクトの属性に乗せて、結果を表示するUI:user_list.jspにフォーワードしているだけで、処理は簡潔です。

ユーザ一覧情報の表示を行うUI:user_list.jspでは、マーキング部が示すようにrequestオブジェクトの属性からユーザ情報をArrayListにに取り出し、拡張For文で一行づつHTMLに配置し表示し、戻るボタンで初期画面に戻れるようにしています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.example.UserDto" %>
<% ArrayList<UserDto> list = (ArrayList<UserDto>)request.getAttribute("list"); %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登録済みユーザ一覧</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/login.css">
</head>
<body>
    <h1>登録済みユーザ一覧</h1>
    <table>
        <tr><th>登録番号</th><th>ユーザID</th><th>パスワード</th></tr>
        <% for (UserDto ud: list) { %>
        <tr>
        <td><%= ud.getNo() %></td>
        <td><%= ud.getUserid() %></td>
        <td><%= ud.getPassword() %></td>
        </tr>
        <% } %>
    </table>
    <br>
    <hr>
    <form action="./login_main.jsp" method="post">
        <button type="submit"><pre><big>戻る</big></pre></button>
    </form>
</body>
</html>

次はユーザのログイン処理のための入力情報を受取るUI:user_login.jspです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ログインフォーム</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/login.css">
</head>
<body>
<h1>ユーザログイン</h1>
<form action="./UserLoginServlet" method="post">
    <table>
        <tr>
            <th>ID</th>
            <th>パスワード</th>
            <th></th>
        </tr>
        <tr>
            <td><input type="text" name="id"  /></td>
            <td><input type="password" name="password" /></td>
            <td><input type="submit" value="実行"></td>
        </tr>
    </table>
</form>
<%
    String error = (String)request.getAttribute("error");
    if (error != null) {
%>
    <p style="color:red; font-size: larger;"><%= error %></p>
<%   } %>
<br>
<hr>
<form action="./login_main.jsp" method="post">
    <button type="submit"><pre><big>戻る</big></pre></button>
</form>
</body>
</html>

ユーザIDとパスワードを受取ったら、ログイン処理のコントロールを行っているサーブレット:UserLoginServletを呼びます。
一方、UserLoginServletで入力情報のエラーを発見するとエラーメッセージをrequestオブジェクトの属性に乗せてuser_login.jspを呼ぶので、本JSPの後半ではエラーメッセージがあれば表示しています。
また、戻るボタンで初期画面に戻るようになっています。

UserLoginServletでは、DAOのfindUserで入力されたユーザ情報が既に登録済か確認し、登録されていればログイン成功としてユーザIDをrequestオブジェクトの属性に乗せuser_login_success.jspを呼び、登録されていなければエラーメッセージをrequestオブジェクトの属性に乗せuser_login.jsp呼びます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.example;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
 
/**
 * Servlet implementation class LoginServlet
 */
@WebServlet("/UserLoginServlet")
public class UserLoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
 
    /**
     * @see HttpServlet#HttpServlet()
     */
    public UserLoginServlet() {
        super();
    }
 
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    request.setCharacterEncoding("UTF-8");
 
    String id = request.getParameter("id");
    String password = request.getParameter("password");
 
    UserDao dao = new UserDao();
    UserDto user = dao.findUser(id);
 
    boolean isLogin = (user != null && id.equals(user.getUserid()) &&
        password.equals(user.getPassword()));
    HttpSession session = request.getSession();
    session.setAttribute("isLogin", isLogin);
 
    if (isLogin) {
        request.setAttribute("username", user.getUserid());
        request.getRequestDispatcher("/user_login_success.jsp").forward(request, response);
    } else {
        request.setAttribute("error", "IDかパスワードが間違っています。\n再入力してください。");
        request.getRequestDispatcher("/user_login.jsp").forward(request, response);
    }
 
    }
}
ログインが成功した場合呼ばれるUIがuser_login_success.jspです。本JSPでは受け取ったユーザIDを使って、ログイン成功のメッセージを表示し、戻るボタンで初期画面に戻れるようにしています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<%@ page language="HTML" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ユーザログイン成功</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/login.css">
</head>
<body>
<h1>ユーザログイン成功</h1>
<hr>
<%
    String username = (String)request.getAttribute("username");
    if (username != null) {
%>
    <p style="color:blue; font-size: larger;">ようこそ<%= username %>さん!</p>
<%   } %>
<br>
<hr>
<form action="./login_main.jsp" method="post">
    <button type="submit"><pre><big>戻る</big></pre></button>
</form>
</body>
</html>

次はユーザの登録処理です。
まず登録のためのユーザ情報を受取るUI:user_regist.jspは、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ログインフォーム</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/login.css">
</head>
<body>
<h1>ユーザ登録</h1>
<form action="./UserRegServlet" method="post">
    <table>
        <tr>
            <th>ID</th>
            <th>パスワード</th>
            <th></th>
        </tr>
        <tr>
            <td><input type="text" name="id"  /></td>
            <td><input type="password" name="password" /></td>
            <td><input type="submit" value="登録"></td>
        </tr>
    </table>
</form>
<%
    String error = (String)request.getAttribute("error");
    if (error != null) {
%>
    <p style="color:red; font-size: larger;"><%= error %></p>
<%   } %>
<br>
<hr>
<form action="./login_main.jsp" method="post">
    <button type="submit"><pre><big>戻る</big></pre></button>
</form>
</body>
</html>

ユーザIDとパスワードを受取ったら、ユーザ登録処理のコントロールを行っているサーブレット:UserRegServletを呼びます。
一方、UserRegServletで入力情報のエラーを発見するとエラーメッセージをrequestオブジェクトの属性に乗せて本jspにフォーワードするので、後半でエラーメッセージがあればそれを表示しています。
また、戻るボタンで初期画面に戻るようになっています。

UserRegServletでは、DAOのfindUserで入力されたユーザ情報が既に登録済か確認し、登録されていればエラーメッセージをrequestオブジェクトの属性に乗せuser_regist.jspにフォーワードし、登録されていなければDAOのregUserを使ってユーザを登録し、ユーザ登録成功としてユーザIDをオブジェクトの属性に乗せuser_reg_success.jspをフォーワードします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.example;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
 
/**
 * Servlet implementation class UserRegServlet
 */
@WebServlet("/UserRegServlet")
public class UserRegServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
 
    /**
     * @see HttpServlet#HttpServlet()
     */
    public UserRegServlet() {
        super();
    }
 
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    request.setCharacterEncoding("UTF-8");
 
    String id = request.getParameter("id");
    String password = request.getParameter("password");
 
    UserDao dao = new UserDao();
    UserDto user = dao.findUser(id);
 
    boolean isLogin = (user != null && id.equals(user.getUserid()) &&
        password.equals(user.getPassword()));
    HttpSession session = request.getSession();
    session.setAttribute("isLogin", isLogin);
 
    if (!isLogin) {
        int result = dao.regUser(id, password);
        request.setAttribute("username", id);
        request.getRequestDispatcher("/user_reg_success.jsp").forward(request, response);
    } else {
        request.setAttribute("error", "同じIDとパスワードのユーザが既に登録されています。\n再入力してください。");
        request.getRequestDispatcher("/user_regist.jsp").forward(request, response);
    }
 
    }
}
ユーザ登録が成功した場合に呼ばれるJSP:user_reg_success.jspは、受け取ったユーザIDを使って、ユーザ登録成功のメッセージを表示し、戻るボタンで初期画面に戻れるようにしています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ユーザ登録成功</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/login.css">
</head>
<body>
<h1>ユーザ登録成功</h1>
<hr>
<%
    String username = (String)request.getAttribute("username");
    if (username != null) {
%>
    <p style="color:blue; font-size: larger;"><%= username %>さんの登録が完了しました。</p>
<%   } %>
<br>
<hr>
<form action="./login_main.jsp" method="post">
    <button type="submit"><pre><big>戻る</big></pre></button>
</form>
</body>
</html>

次はユーザの削除処理です。
まず削除するユーザの情報を入力するUI:user_delete.jspです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ログインフォーム</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/login.css">
</head>
<body>
<h1>ユーザ削除</h1>
<form action="./UserDelServlet" method="post">
    <table>
        <tr>
            <th>ID</th>
            <th>パスワード</th>
            <th></th>
        </tr>
        <tr>
            <td><input type="text" name="id"  /></td>
            <td><input type="password" name="password" /></td>
            <td><input type="submit" value="削除"></td>
        </tr>
    </table>
</form>
<%
    String error = (String)request.getAttribute("error");
    if (error != null) {
%>
    <p style="color:red; font-size: larger;"><%= error %></p>
<%   } %>
<br>
<hr>
<form action="./login_main.jsp" method="post">
    <button type="submit"><pre><big>戻る</big></pre></button>
</form>
</body>
</html>

ユーザIDとパスワードを受取ったら、ユーザ削除処理のコントロールを行っているサーブレット:UserDelServletを呼びます。
一方、UserDelServletで入力情報のエラーを発見するとエラーメッセージをrequestオブジェクトの属性に乗せて本jspにフォーワードするので、後半でエラーメッセージがあればそれを表示しています。
また、戻るボタンで初期画面に戻るようになっています。

UserDelServletでは、DAOのfindUserで入力されたユーザ情報が既に登録済か確認し、登録されていればDAOのdelUserを使ってユーザを削除し、ユーザ削除成功としてユーザIDをオブジェクトの属性に乗せuser_del_success.jspにフォーワードし、登録されていなければエラーメッセージをrequestオブジェクトの属性に乗せuser_delete.jspにフォーワードします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.example;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 * Servlet implementation class UserDelServlet
 */
@WebServlet("/UserDelServlet")
public class UserDelServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
 
    /**
     * @see HttpServlet#HttpServlet()
     */
    public UserDelServlet() {
        super();
 
    }
 
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    request.setCharacterEncoding("UTF-8");
 
    String id = request.getParameter("id");
    String password = request.getParameter("password");
 
    UserDao dao = new UserDao();
    UserDto user = dao.findUser(id);
 
    boolean isLogin = (user != null && id.equals(user.getUserid()) &&      
        password.equals(user.getPassword()));
 
    if (isLogin) {
        int result = dao.delUser(id, password);
        request.setAttribute("username", id);
        request.getRequestDispatcher("/user_del_success.jsp").forward(request, response);
    } else {
        request.setAttribute("error", "該当するIDとパスワードのユーザは登録されていません。\n再入力してください。");
        request.getRequestDispatcher("/user_delete.jsp").forward(request, response);
    }
 
    }
}
ユーザ削除が成功した場合に呼ばれるJSP:user_del_success.jspは、受け取ったユーザIDを使って、ユーザ削除成功のメッセージを表示し、戻るボタンで初期画面に戻れるようにしています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ユーザ削除成功</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/login.css">
</head>
<body>
<h1>ユーザ削除成功</h1>
<hr>
<%
    String username = (String)request.getAttribute("username");
    if (username != null) {
%>
    <p style="color:blue; font-size: larger;"><%= username %>さんの登録を削除しました。</p>
<%   } %>
<br>
<hr>
<form action="./login_main.jsp" method="post">
    <button type="submit"><pre><big>戻る</big></pre></button>
</form>
</body>
</html>

最後に処理の中で度々呼ばれていたDAOとDTOを示します。
DAOはJDBCを使ってデータベースに対するConnection及びclose処理を行い、必要なデータベース操作のSQL文を発行し、結果をDTOに格納する各種のメソッドを提供しています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package com.example;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
 
public class UserDao {
 
    private static Connection getConnection() {
        try {
            Class.forName("org.postgresql.Driver");
            return DriverManager.getConnection("jdbc:postgresql:login","postgres", "root");
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
    }
 
    private static void allClose(PreparedStatement statement, Connection connection) {
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
 
    }
 
    static Connection connection = null;
    static PreparedStatement statement = null;
 
    public UserDto findUser(String id) {
        UserDto user = new UserDto();
 
        try {
            connection = getConnection();
 
            statement = connection.prepareStatement("SELECT * FROM userinf WHERE userid = ?");
            statement.setString(1, id);
            ResultSet resultSet = statement.executeQuery();
 
            if (!resultSet.next()) { return null; }
 
            user.setUserid(resultSet.getString("userid"));
            user.setPassword(resultSet.getString("password"));
 
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            allClose(statement, connection);
        }
        return user;
 
    }
    public ArrayList<UserDto> getUserList() {
        ArrayList<UserDto> list = new ArrayList<UserDto>();
 
        try {
            connection = getConnection();
 
            statement = connection.prepareStatement("SELECT * FROM userinf");
            ResultSet resultSet = statement.executeQuery();
 
            while (resultSet.next()) {
                UserDto ud = new UserDto();
                ud.setNo(resultSet.getInt(1));
                ud.setUserid(resultSet.getString(2));
                ud.setPassword(resultSet.getString(3));
                list.add(ud);
            }
 
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            allClose(statement, connection);
        }
        return list;
 
    }
 
    public int regUser(String id, String password) {
        int result = 0;
 
        try {
            connection = getConnection();
 
            statement = connection.prepareStatement("INSERT INTO userinf (userid, password) VALUES (?, ?)");
            statement.setString(1, id);
            statement.setString(2, password);
            result = statement.executeUpdate();
 
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            allClose(statement, connection);
        }
        return result;
 
    }
 
    public int delUser(String id, String password) {
        int result = 0;
 
        try {
            connection = getConnection();
 
            statement = connection.prepareStatement("DELETE FROM userinf WHERE userid = ? AND password = ?");
            statement.setString(1, id);
            statement.setString(2, password);
            result = statement.executeUpdate();
 
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            allClose(statement, connection);
        }
        return result;
 
    }
 
}
そしてDTOはビジネスロジックが必要とするオブジェクト情報へのgetterとsetterを提供します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.example;
 
public class UserDto {
    private int no;
    private String userid;
    private String password;
 
    public int getNo() {
        return no;
    }
    public String getUserid() {
        return userid;
    }
    public String getPassword() {
        return password;
    }
 
    public void setNo(int no) {
        this.no = no;
    }
    public void setUserid(String userid) {
        this.userid = userid;
    }
    public void setPassword(String password) {
        this.password = password;
    }
 
}

以上のようにDAOを使うことでJSPやServletの数は増えますが、全体構造は簡潔になり保守性、拡張性が向上しログイン処理(書き下し版)とは異なる形になった事が分かるでしょう。

次のステップ:ログイン処理(DAOを使った汎用的で現実的な構造)
ではDAOを使ったより汎用的で、現実的な構造を考えます。

カテゴリー: JSP_Servlet | タグ: , , , , , , , | ログイン処理(Daoを使った改良版) はコメントを受け付けていません

Eclipseで実行するJSPが外部cssをlink指定する場合の注意

JSPが外部cssファイルをlinkする場合の指定法はJSPで外部cssをlink指定する

<link rel="stylesheet" href="${pageContext.request.contextPath}/xxxxx.css">

と指定すればよいと説明しました。

しかし、link指定する外部cssファイルをファイルシステム上のコンテキストルート直下においても、EclipseでTomcatを使用している場合はさらに小技が必要です。
つまり、Eclipseのプロジェクト・エクスプローラーにそのファイルが現れない限り、Eclipseに組み込まれたTomcatからはそのファイルを認識できません。そこで、ブラウザからget要求が来ても、相変わらず404エラーを出してしまいます。
つまり、外部cssファイルの配置はWindowsのエクスプローラ上で行うのではなく、適当な所に置いたファイルをドラッグアンドドロップでEclipseのプロジェクト・エクスプローラ上の所定の場所に配置しなければなりません。こうすればEclipseがファイルを認識してプロジェクト・エクスプローラ上にも表示されます。

外部cssファイルをEclipseのプロジェクト・エクスプローラにドラッグ&ドロップ

カテゴリー: eclipse | タグ: , , , , | Eclipseで実行するJSPが外部cssをlink指定する場合の注意 はコメントを受け付けていません

JSPで外部cssをlink指定する

コンテキストルート直下にあるJSPで同じ階層に置いた外部cssファイルをlink指定する場合、通常の指定法

<link rel="stylesheet" href="xxxx.css">

では、コンテキストルート経由の指定でないためか内部で404(Not Found error)が出てしまいます。そこで、

<link rel="stylesheet" href="${pageContext.request.contextPath}/xxxxx.css">

とすると、正しくlink情報が渡りTomcatを単体で動かしている場合はcssがJSPに取り込まれます。

なお、cssの配置場所としては外部cssはブラウザがgetするので外部から参照できる階層に置かなければいけないでしょう。そこでWEB-INFなどの中ではなくコンテキスストルート直下かそこに作ったフォルダー内が良いでしょう。

<Tomcatを単体で動かしている場合は>と書いたのはEclipseでTomcatを使っている場合は、さらに注意が要ります。link指定する外部cssファイルをファイルシステム上コンテキストルート直下においても、Eclipseのエクスプローラーにそのファイルが現れない限り、Eclipseに組み込まれたTomcatからはそのファイルが見えないのでブラウザからget要求が来ても、404エラーを出すという事です。
これの対処法についてはEclipseについての記事:Eclipseで実行するJSPが外部cssをlink指定する場合の注意で説明しているので参照してください。

カテゴリー: JSP_Servlet | タグ: , , | JSPで外部cssをlink指定する はコメントを受け付けていません

WordPress tweenteen_ten コンテンツレイアウト tips

WordPress tweenteen_ten を使った「ITツールの使い方」用コンテンツレイアウトのtips

  1. コンテンツの横幅は640px

  2. コンテンツを横3分割するには

    <div class="subDivLeft">
    1. 初期画面
    <a href="xxxx">
    <img class="imgW200" class="xxxx" /></a>
    </div>

  3. 画像を表示する

    <img  src="/wp/wp-content/uploads/2017/06/simpleLogin01.png" alt="ログイン処理(書き下し版)01" />

  4. 画像をクリックして拡大画像を別タブに表示する

    <img  class="xxx.png" alt="xxxxxx" /></a>

  5. リンク先のページ名を角Rの付いたボタン形状で表示し、aタグでリンクを貼る

    <a  class="btnInText" href="http://fksekiguchi.sakura.ne.jp/wp/others/link4outsidecssinjsp">JSPで外部cssをlink指定する</a>

  6. コンテンツにソースコードを挿入、一部の行をマーキング、行番号の表示をしない

    〔code language="HTML" highlight="3, 7-15, 19-22, 27-29" gutter="false"〕

    くわしくはWordPressのコンテンツにプログラムコードを書き込むまたはWordPress内でHTMLソースなどを表示を参照ください。

  7. floatレイアウトをキャンセルする

    <div class="clearW600"></div>

  8. 簡易ホルダー構造記入

    Object
     ┃
    Throwable
     ┣━Error
     ┗━Exception
        ┗━RuntimeException

  9. 現在のカスタムCSSは(201707/19)

    /*
    カスタム CSS
    */
    .pictureLeft {
        margin: 0 10px 10px 0;
        float: left;
        display: inline;
    }
     
    .imgTitle {
        text-align: center;
    }
     
    img.waku {
        border: 1px solid #dddddd;
    }
     
    .imgW300 {
        padding: 5px;
        border-width: 2px;
        border-style: solid;
        border-color: black;
        width: 300px;
    }
     
    /* add 2017/0612 */
    .subDivLeft {
        margin-right: 10px;
        float: left;
    }
     
    .imgW640, .imgW310, .imgW200 {
        margin-top: -1.5em;
    /* aタグ1行分を引き上げる */
        border-width: 2px;
        border-style: solid;
        border-color: black;
        text-align: left;
    }
     
    .imgW640 {
        width: 640px;
    }
     
    .imgW310 {
        width: 310px;
    }
     
    .imgW200 {
        width: 200px;
    }
     
    .imgCommLeft {
        margin-top: -25px;
        text-align: left;
        font-size: small;
        font-weight: lighter;
        width: 200px;
    }
     
    .clearW600 {
        width: 600px;
        height: 10px;
        clear: both;
    }
     
    .FloatClear {
        width: 640px;
        height: 0;
        clear: both;
    }
     
    button.btnInText {
        border: solid 2px;
        border-radius: 5px;
        border-color: ##4f4f4f;
        background-color: #efefef;
        color: #6f6f6f;
        margin: 0 .3em;
        padding: 0 .2em;
        text-decoration: none;
    }
     
    a.btnInText {
        border: solid 2px;
        border-radius: 5px;
        border-color: ##4f4f4f;
        background-color: #efefef;
        color: #6f6f6f;
        margin: 0 .3em;
        padding: 0 .2em;
        text-decoration: none;
    }
     
    a.dispbk {
        margin-bottom: -1em;
        display: block;
        width: 12em;
        text-align: center;
    }
     
    table, th, td {
        border: 1px solid;
        width: auto;
        padding: 1px;
        font-size: small;
    }
     
    .mgnTopUP {
        margin-top: -1.5em;
    /* aタグ1行分を引き上げる */
    }
     
    .tab1 {
        padding-left: 20px;
        width: 620px;
        float: left;
    }
     
    .tab2 {
        padding-left: 40px;
        width: 600px;
        float: left;
    }
     
    .tab3 {
        padding-left: 80px;
        width: 560px;
        float: left;
    }

  10. 箇条書き

項目タイトル
タイトルに対する説明。もし、タイトルと同じ行に説明を書きたいのであればclass指定にmgnTopUPを追加します。
<div>項目タイトル</div><div class="tab3">ここに説明</div>
カテゴリー: WP 機能 | コメントする

抽象クラスとインターフェース

抽象クラスもインターフェースも通常のクラスとのコーディング上の違いを理解しても、実際のプログラミングではどのように使い分けたらよいのでしょうか。
どのような場合はクラス、どのような場合に抽象クラス、そしてどういう時にはインターフェースを使ってプログラミングすれば良いのか、いくつかのガイドを整理します。

クラスと抽象クラスの使い分け
クラスはもともと(狭義の)オブジェクトを抽象化して作ります。
では抽象クラスは一般的なクラスと何が違うのでしょう。本題に入る前に「抽象」という言葉を正しく理解しましょう。
「抽象」というと抽象画の印象や、「具象」の反対語だから「曖昧な」といった意味だろうと思っている人もいます。ですが英語のabstractには「曖昧な」という意味はありません。英語の辞書を見ると、動詞として「~を取り除く」「~を概念化する」「~要約する」とあります。
ここで概念化とは「いくつかの事物を一般化して考えるさま」ですから、抽象化とは「個別的な物を取り除いて、事物に共通なものを抜き出し、要約する」ことです。クラスは個々のオブジェクトから個別的な物を取り除き、共通する点を抜き出して、具体的なフィールドとメソッドに要約してスーパークラスとし、各オブジェクト固有の事物をサブクラスで定義します。
一方、抽象クラスはこの抽象化を一歩進めて、個別的な物の中で振舞いの中身は違っていても、共通して持っている振舞いを中身を定義しない抽象メソッドとして定義し、サブクラスに具体的な振舞の中身を定義させます。従って抽象クラスは通常のスーパークラスが行わない定義すべき振舞いをサブクラスに強制力を持って規定します。

抽象クラスとインターフェース
一般的なクラスと違いはあるといっても抽象クラスはクラスですからobjectからのクラスの階層構造のどこかに位置します。一方インターフェースは外見的に抽象クラスと似ていてもクラスではないので、この階層構造の中には位置しません。
インターフェースは特定のクラスに付随するだけです。このためクラスが継承されるのに対し、インターフェースは実装されるという違いになります。この点こそが抽象クラスとインターフェースの違いであり、使い分けのポイントです。
意味から考えるとインターフェースは「つなぎ合わせる」「調和させる」とあります。では何をつなぎ合わせ、調和させるのでしょう。
実際の開発では大勢のプログラマがプログラミングを分担し、数多くの機能(振舞い)を開発するので、全ての開発が同期して開発できるわけではありません。つまりある部分を開発し、テストしようとしても関連する別の部分はまだ設計中で結合してテストすることが出来なかったり、開発している場所が離れていてリアルタイムで開発を同期させることが出来なかったり、そもそもシステムが複雑で部分部分を個別にテストしてからでないと結合してテストが出来なかったりします。
このような場合、インターフェースを使えば複雑なシステムをモジュールに分解して、モジュール単位で開発を進め、単体テストが終わったら実装モジュールを実際の物に入れ替えて総合テストを行う事ができます。つまりインターフェースは実装の仕方は問わずに相手にしてもらいたい事だけを定義し、自分と相手モジュールをつなぎます。このため抽象クラスと違って相手に与える定数と相手に求める振舞いとしての抽象メソッドしか記述しません。

カテゴリー: Java | タグ: , | 抽象クラスとインターフェース はコメントを受け付けていません