TanukiEngineerの1歩ずつ進もうよ!

まだまだ駆け出しエンジニアの学習メモ

Eclipse インポートされたjavax.servlet.○○は見付かりません」というエラーメッセージが表示された場合の対処方法

「インポートされたjavax.servlet.○○は見付かりません」というエラーメッセージが表示された場合の対処方法

f:id:TanukiEngineer:20210806093701p:plain
エラーメッセージ

「ビルド・パス」>「ビルド・パスの構成」を選択します。

f:id:TanukiEngineer:20210806093756p:plain
ビルド・パスの構成を選択

Javaのビルド・パス】設定画面で「外部JARの追加」を選択します。

f:id:TanukiEngineer:20210806093835p:plain
外部JARの追加

自分の環境でtomcatがインストールされているフォルダから「servlet-api.jar」を選択して[開く]を押下します。

f:id:TanukiEngineer:20210806093942p:plain
servlet-api.jar」を選択

servlet-api.jar」が追加されたことを確認して、[適用して閉じる]を押下します。

f:id:TanukiEngineer:20210806094016p:plain
servlet-api.jar」確認

エラーメッセージが消えたことを確認します。

f:id:TanukiEngineer:20210806094110p:plain
エラー解消を確認

Visual Studio Code ターミナルでファイルを表示すると文字化けしていた場合の文字化け解消方法

文字化けの例

UTF-8のファイルをPoweShellで表示すると、次のように文字化けしていました。

f:id:TanukiEngineer:20210219104227p:plain
文字化けの例

文字化けの解消方法

文字化けを解消するため、読み込むファイルのエンコードを変更します。
VSCodeでそのファイルを開いて、VSCode画面下の「UTF-8」の部分をクリックします。

f:id:TanukiEngineer:20210219104312p:plain
エンコードの変更

下記のように選択肢が表示されるので「エンコード付きで保存」を選択します。

f:id:TanukiEngineer:20210219104455p:plain
エンコード付きで保存

PowerShellで開く場合、SJIS・UTF-8BOM・UTF-16のファイルであれば設定を変更せずに読み込めます。
今回はUTF-8 with BOMを選択しました。
SJISUTF-16でも同様に文字化けしないことが確認できました。

f:id:TanukiEngineer:20210219104535p:plain
UTF-8 with BOMを選択

再度、文字化けしていたファイルを表示すると、文字化けが解消されたことが確認できました。

f:id:TanukiEngineer:20210219104645p:plain
実行結果 文字化け解消

参考にした記事:

文字化け - vscodeのターミナルが文字化けする - スタック・オーバーフロー

デザインパターン:Template Method(テンプレートメソッド)パターン

Template Methodパターンとは

  • Template Methodパターンは、テンプレートの機能を持つパターンです。
  • スーパークラスの方にテンプレートとなるメソッドが定義されています。
  • その定義の中では抽象メソッドが使われています。
  • このため、スーパークラスのプログラムを読んでいるだけでは、最終的にどんな処理をすることになるかは分かりません。
  • わかることは、抽象メソッドをどのように呼び出しているか、ということだけです。
  • 抽象メソッドを実際に実装するのはサブクラスです。
  • サブクラスの側でメソッドを実装すれば、具体的な処理が決定します。
  • 異なるサブクラスが異なる実装を行えば、異なる処理が行われます。
  • しかし、どのサブクラスでどのような実装をしたとしても、処理の大きな流れはスーパークラスで組み立てたとおりになります。
  • このように、スーパークラスで処理の枠組みを定め、サブクラスでその具体的な内容を定めるようなデザインパターンを、「Template Methodパターン」と呼びます。

Template Methodパターンを使うメリットについて

ロジックが共通化できる

  • スーパークラスのテンプレートメソッドでアルゴリズムが記述されているので、サブクラス側ではアルゴリズムをいちいち記述する必要がなくなります。
  • もし、Template Methodパターンを使わず、複数のクラスにロジック部分をコピペしていると、バグが発見されたときに、ロジックが書かれているすべてのクラスを修正しなければならなくなります。
    Template Methodパターンでプログラミングしていれば、テンプレートメソッドに誤りが発見された場合は、テンプレートメソッドのみ修正すればよいことになります。

サンプルプログラム

クラス一覧

名前 説明
Shopping.java メソッドtoShoppingのみ実装されている抽象クラス
OnlineShop.java メソッドchooseProduct, goToCashRegister, Payを実装しているクラス
RealStore.java メソッドchooseProduct, goToCashRegister, Payを実装しているクラス
Main.java 動作テスト用のクラス

クラス図

f:id:TanukiEngineer:20210211094440p:plain
クラス図_TemplateMethodのサンプル

Shopping.java

public abstract class Shopping {
    public abstract void chooseProduct();
    public abstract void goToCashRegister();
    public abstract void pay();
    public void toShopping() {
        chooseProduct();
        goToCashRegister();
        pay();
    }
}

RealStore.java

public class RealStore extends Shopping {
    private String product;
    public RealStore(String product) {
        this.product = product;
    }

    @Override
    public void chooseProduct() {
        System.out.println("***リアル店舗でお買い物***\n");
        System.out.println("陳列棚から「" + product + "」を選びました。");
    }
    
    @Override
    public void goToCashRegister() {
        System.out.println("レジに並びます。\n人が少ない列に並びました。");
    }
    
    @Override
    public void pay() {
        System.out.println("端末に電子マネーのカードをかざして支払いをしました。\n");
    }
}

OnlineShop.java

public class OnlineShop extends Shopping {
    private String product;
    public OnlineShop (String product) {
        this.product = product;
    }
    
    @Override
    public void chooseProduct() {
        System.out.println("***ネットショッピング***\n");
        System.out.println("商品リストから「" + product + "」を選びました。");
    }
    
    @Override
    public void goToCashRegister() {
        System.out.println("レジへ行くボタンを押下しました。");
    }
    
    @Override
    public void pay() {
        System.out.println("クレジットカードで支払いをしました。\n");
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        Shopping sh1 = new RealStore("アイスクリーム");
        Shopping sh2 = new OnlineShop("地方の名産品");
    
        sh1.toShopping();
        sh2.toShopping();
    }
}

実行結果

***リアル店舗でお買い物***

陳列棚から「アイスクリーム」を選びました。
レジに並びます。
人が少ない列に並びました。
端末に電子マネーのカードをかざして支払いをしました。

***ネットショッピング***

商品リストから「地方の名産品」を選びました。
レジへ行くボタンを押下しました。
クレジットカードで支払いをしました。
参考:詳しくは、以下の書籍を参照してください
  • 「補講:クラス階層と抽象クラス」も参考になります
  • 練習問題もあります

増補改訂版Java言語で学ぶデザインパターン入門 | 結城 浩 |本 | 通販 | Amazon

デザインパターン:Prototype(プロトタイプ)パターン

Prototype パターンとは

クラスからインスタンスを生成するのではなく、インスタンスから別のインスタンスを作り出すパターンをPrototype(プロトタイプ)パターンと呼びます。

  • prototypeという英単語は、「原型」や「模範」という意味です。
  • prototypeのインスタンスを元に新しいインスタンスを作ります。
  • Java言語では、複製を作る操作を「clone(クローン)」と呼びます。
  • クラスのインスタンスを作成するとき、Javaでは、newというキーワードを使って、クラス名を指定することでインスタンスを生成します。
  • 例えば、Somethingクラスのインスタンスを作成する場合は、次のような式を書きます。
new something()

Prototypeパターンのクラス図

f:id:TanukiEngineer:20210207150133p:plain

サンプルプログラム

以下、Prototypeパターンを使ったサンプルプログラムです。

クラスとインターフェース一覧
パッケージ 名前 説明
framework Product 抽象メソッドuseとcreateCloneが
宣言されているインターフェース
framework Manager createCloneを使ってインスタンス
複製するクラス
無名 ConcreteProduct ・createCloneを実装
・MessageBoxクラス等のスーパークラス
無名 MessageBox ・文字列を枠線で囲って表示するクラス
・useとcreateCloneを実装
無名 UnderlinePen ・文字列に下線を引いて表示するクラス
・useとcreateCloneを実装
無名 ReplayQuote ・文字列の前に引用符を表示するクラス
・useとcreateCloneを実装
無名 Main 動作テスト用のクラス

サンプルプログラムのクラス図

f:id:TanukiEngineer:20210207221726p:plain

Productインタフェース

  • java.lang.Cloneableインタフェースを継承しています。
  • このインタフェースを実装しているクラスは、cloneメソッドを使用して自動的に複製ができるようになります。
  • useメソッドは、名前のとおり「使う」ためのメソッドです。何をどのように「使う」かはサブクラスの実装に任されます。
  • createCloneメソッドは、インスタンスの複製を行うためのものです。

Product.java

package SampleDesignPattern.framework;

public interface Product extends Cloneable {
    public abstract void use(String s);
    public abstract Product createClone();
}

Managerクラス

  • Managerクラスは、Productインターフェースを利用してインスタンスの複製を行うクラスです。
  • showcaseフィールドは、java.util.HashMapでインスタンスの「名前」と「インスタンス」の対応関係を表現したものです。
  • registerメソッドは、引数で渡された製品の名前とProductインターフェースの1組を登録します。
  • Managerクラスには、Productインターフェースを実装した具体的なクラス名は出てきません。そのため、具体的なクラスとは独立に修正できることを意味しています。ソース中にクラスの名前を書いてしまうと、そのクラスと密接な関係ができてしまします。
  • オブジェクト指向プログラミングの目標の1つである「部品としての再利用」をするため、ソースファイル(.java)がなくても、クラスファイル(.class)があれば再利用できる、ようにしています。

Manager.java

package SampleDesignPattern.framework;
import java.util.HashMap;

public class Manager {
    private HashMap<String, Product> showcase = new HashMap<String, Product>();
    public void register(String name, Product proto) {
        showcase.put(name, proto);
    }
    public Product create(String protoname) {
        Product p = (Product)showcase.get(protoname);
        return p.createClone();
    }
}

ConcreteProduct

  • サブクラスで実装するcreateCloneメソッドは共通の処理であるため、Productインターフェースを実装し、ここでcreateCloneを実装します。
  • createCloneメソッドは、cloneメソッドを使用し、自分自身の複製を行うメソッドです。
  • Java言語のcloneメソッドは、自分のクラス(およびサブクラス)からしか呼び出すことができないため、creageCloneメソッドを作成して、その中でcloneメソッドを使うようにしています。
  • useメソッドは各サブクラスで処理内容が異なるため、抽象メソッドのままとします。

ConcreteProduct.java

package SampleDesignPattern.PrototypePattern;

import SampleDesignPattern.framework.Product;

public abstract class ConcreteProduct implements Product {
    public abstract void use(String s);
    @Override
    public Product createClone() {
        Product p = null;
        try {
            p = (Product)clone();
        }
        catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}

MessageBoxクラス

  • 具体的なサブクラス。ConcreteProductクラスを継承しています。
  • useメソッドは、引数で渡された文字列に対して、decocharフィールドの文字で囲みます。

MessageBox.java

package SampleDesignPattern.PrototypePattern;

public class MessageBox extends ConcreteProduct {
    private char decochar;
    public MessageBox(char decochar) {
        this.decochar = decochar;
    }

    @Override
    public void use(String s) {
        int length = s.getBytes().length;
        for (int i = 0; i < length + 4; i++) {
            System.out.print(decochar);
        }
        System.out.println("");
        System.out.println(decochar + " " + s + " " + decochar);
        for (int i = 0; i < length + 4; i++) {
            System.out.print(decochar);
        }
        System.out.println("");
    }
}

UnderlinePenクラス

  • 具体的なサブクラス。ConcreteProductクラスを継承しています。
  • useメソッドは、引数で渡された文字列に対して、二重引用符""でくくり、文字列の下にulcharフィールドの文字で下線を引きます。

UnderlinePen.java

package SampleDesignPattern.PrototypePattern;

public class UnderlinePen extends ConcreteProduct {
    private char ulchar;
    public UnderlinePen(char ulchar) {
        this.ulchar = ulchar;
    }

    @Override
    public void use(String s) {
        int length = s.getBytes().length;
        System.out.println("\"" + s + "\"");
        System.out.print(" ");
        for (int i = 0; i < length; i++) {
            System.out.print(ulchar);
        }
        System.out.println("");
    }
}

ReplayQuoteクラス

  • 具体的なサブクラス。ConcreteProductクラスを継承しています。
  • useメソッドは、引数で渡された文字列の先頭にquotecharフィールドの文字を付与します。

ReplayQuote.java

package SampleDesignPattern.PrototypePattern;

public class ReplayQuote extends ConcreteProduct {
    private char quotechar;

    public ReplayQuote(char quotechar) {
        this.quotechar = quotechar;
    }

    @Override
    public void use(String s) {
        System.out.println(quotechar + " " + s);
    }
}

Mainクラス

名前 クラス インスタンスの内容
"strong message" UnderlinePen ulchar:'~'
"warning box" MessageBox decochar:'*'
"slash box" MessageBox decochar:'/'
"greater than quote" ReplayQuote quotechar:'>'

Main.java

package SampleDesignPattern.ReplayQuotePrototypePattern;
import SampleDesignPattern.framework.*;

public class Main {
    public static void main(String[] args) {
        // 準備
        Manager manager = new Manager();
        UnderlinePen upen = new UnderlinePen('~');
        MessageBox mBox = new MessageBox('*');
        MessageBox sBox = new MessageBox('/');
        ReplayQuote gQuotes = new ('>');
        manager.register("strong message", upen);
        manager.register("warning box", mBox);
        manager.register("slash box", sBox);
        manager.register("greater than quote", gQuotes);

        // 生成
        Product p1 = manager.create("strong message");
        p1.use("Hello, World.");
        Product p2 = manager.create("warning box");
        p2.use("Hello, world.");
        Product p3 = manager.create("slash box");
        p3.use("Hello, world.");
        Product p4 = manager.create("greater than quote");
        p4.use("Hello, world.");
    }
}

【実行結果】

"Hello, World."
~~~~~~~~~~~~~
*****************
* Hello, world. *
*****************
/////////////////
/ Hello, world. /
/////////////////
> Hello, world.

参考:詳しくは、以下の書籍を参照してください
  • 「補講:cloneメソッドとjava.lang.Cloneableインターフェース」も参考になります
  • 練習問題もあります

増補改訂版Java言語で学ぶデザインパターン入門 | 結城 浩 |本 | 通販 | Amazon

デザインパターン:Singleton(シングルトン)パターン

Singleパターンの概要

  • インスタンスが1個しか存在しないことを保証するパターンをSingletonパターンと呼びます。

    • 指定したクラスのインスタンスが絶対に1個しか存在しないことを保証したい

    • インスタンスが1個しか存在しないことをプログラム上で表現したい

    • 例えば、コンピュータそのものを表現したクラス、現在のシステム設定を表現したクラス、ウインドウシステムを表現したクラスなどである

  • singletonとは、要素を1個しかもたない集合のことです

サンプルプログラム

表 クラス一覧

名前 説明
Singleton インスタンスが1つしか存在しないクラス
Main 動作テスト用のクラス

クラス図
f:id:TanukiEngineer:20210203055636p:plain


以下、各クラスの説明

Singletonクラス

  • インスタンスは1つしか作られません。
  • staticフィールド(クラス変数)としてsingletonを定義し、Singletonクラスのインスタンスで初期化します。
  • この初期化はSingletonクラスのロード時に一度だけ行われます。
  • コンストラクタはprivateにします。privateにする理由は以下のとおりです。
  • Singletonクラスの唯一のインスタンスを得るための static メソッドを定義します。ここでは、getInstance()という名前にしています。

Singleton.java

public class Singleton {
    private static Singleton singleton = new Singleton();
    private Singleton() {
        System.out.println("インスタンスを生成しました");
    }
    public static Singleton getInstance() {
        return singleton;
    }
}

Mainクラス

  • SingletonクラスのgetInstanceメソッドを呼び出しSingletonのインスタンスを取得します。
  • インスタンスが1つしか存在しないことを確認するため、getInstanceメソッドを2回呼び出しそれぞれobj1とobj2に代入し、obj1 == obj2でテストしています。

Main.java

public class Main {
    public static void main(String[] args) {
        System.out.println("Singletonプログラム開始");
        Singleton obj1 = Singleton.getInstance();
        Singleton obj2 = Singleton.getInstance();
        if (obj1 == obj2) {
            System.out.println("obj1とobj2は同じインスタンスです");
        } else {
            System.out.println("obj1とobj2は異なるインスタンスです");
        }
        System.out.println("Singletonプログラム終了");
    }
}

実行結果:

Singletonプログラム開始
コンストラクタ:インスタンスを生成しました
obj1とobj2は同じインスタンスです
Singletonプログラム終了
  • プログラムが開始後、getInstanceメソッドを呼び出したときに Singletonクラスが初期化され static フィールドの初期化が行われ、唯一のインスタンスが生成されます。
  • 実行結果から、Singletonパターンの目的どおりインスタンスが1つしか存在しないことを保証できることが確認できました。

参考:詳しくは、以下の書籍を参照してください(練習問題もあります)。

増補改訂版Java言語で学ぶデザインパターン入門 | 結城 浩 |本 | 通販 | Amazon

Visual Studio CodeでPlantUMLの拡張機能を追加する

Visual Studio CodeでPlantUMLを使えるようにするには以下の手順で設定します。

次の参考サイトの手順に従って準備します。

Visual Studio Codeの設定を変更する

  1. 「ファイル」メニュー → ユーザー設定 → 設定 を選択する。

    f:id:TanukiEngineer:20210131192958p:plain

  2. メニューから「よく使用するもの」を選択します。
    • 「Files:AutoSave」:「afterDelay」を選択する。これを選択すると自動保存されるようになります。
    • 「Editor:Font Size」:フォントサイズを14に設定します。
    • 「Editor:Font Family」:プログラミング用フォントの「Ricty Diminished」を選択します。
    • 「Editor:Tab Size」:Tabキーを押したときに空白を何文字入れるかを設定します。今回は「4」を設定しています。
    • 「Editor:Render Whitespace」:半角空白文字を表示するかどうかを設定します。意図しない空白文字が入ることで不具合につながることを防止するため、「all」を選択します。

      f:id:TanukiEngineer:20210131193538p:plain

    • 「Editor:Word Wrap」:行の折り返しを設定します。「on」を選択します。

      f:id:TanukiEngineer:20210131193112p:plain

  3. メニューから「テキストエディター」→「ファイル」を選択します。
    • 「Files:Auto Save Delay」:上記で自動保存するよう設定した場合、何ミリ秒後に自動保存するかを設定できます。

      f:id:TanukiEngineer:20210131193825p:plain