Java言語で学ぶデザインパターン入門(増補改訂版)2020年対応コードに修正してみた

名著として名高い「増補改訂版 Java言語で学ぶデザインパターン入門」(2004年刊)の電子書籍がアマゾンKindleで半額になっているので(2020/9/10まで)、この機会に先日購入して読んでいます。

本当にいい本なのだけど、惜しむらくは近年のJavaに対応しておらず、実際にコンパイルしてみると初めの章の数か所でエラーが出ます(それもなぜか練習問題に多い…これでは初学者の読者が通読を断念しかねずもったいない…)

著者の方のWEBを拝見したところ、近年のJava未対応の部分に関しては、サンプルプログラムダウンロードへの反映や訂正欄への掲載はされていない模様です。

色んな人が初心者向けに勧めている本だけどエラーについて言及したものがほとんどなかったので(アマゾンのレビューの一部で見かけた位)、僭越ながら私の分かる範囲内で2020年現在コンパイルが通るコードに修正してみました。

 

今まで読んだ1章から6章が掲載範囲です。3、5、6章でエラーは出ませんでした。
追記:8章のエラーを追加しました。
下記コードで色のついている箇所が変更箇所です。

開発環境は以下の通りです。

OS: Windows10(64bit) [Windows_NT x64 10.0.18363]
Java:JDK-14
Visual Studio Code 1.48.2, Windows PowerShell
Eclipse 2020-06 (Pleiades)

 

第1章 Iterator

練習問題1-1 ListA1-1(BookShelf.java)

import java.util.ArrayList; 

public class BookShelf implements Aggregate {
    private ArrayList<Book>books;
    public BookShelf(int initialsize) {
        this.books = new ArrayList<Book>(initialsize); 
    }
    public Book getBookAt(int index) {
        return (Book)books.get(index);
    }
    public void appendBook(Book book){
        books.add(book); 
    }
    public int getLength() {
        return books.size();
    }
    public Iterator iterator() {
        return new BookShelfIterator(this);
    }
}

◇警告:[unchecked] raw型ArrayListのメンバーとしてのadd(E)への無検査呼出しです
Eが型変数の場合:
クラス ArrayListで宣言されているE extends Object

◇エラーへの対処:ArraylistからArrayList<Book>に変更
該当箇所(ジェネリクス)については「スッキリわかる Java入門 実践編 第2版 」の解説がわかりやすいのでお勧めします。

◇参考:*警告:[unchecked] raw 型 java.util.ArrayList のメンバとしての add(E) への無検査呼び出しです

◇参考:Using ArrayList<Book> to store book titles(翻訳:ArrayList<Book>を使用して本のタイトルを保存する)

 

第2章    Adapter

練習問題2-2 ListA2-1(FileProperties.java)


import java.io.*;
import java.util.*;

public class FileProperties extends Properties implements FileIO {
    public void readFromFile(String filename) { 
        try(FileReader filereader = new FileReader(filename)){
            int data;
            while((data = filereader.read()) != -1) {
            System.out.print((char) data);
            }
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
    public void writeToFile(String filename) {
        try(FileWriter writer = new FileWriter(filename)) {
            store(writer,"written by FileProperties");
        } catch(IOException e) {
            e.printStackTrace();
        }
    }
    public void setValue(String key, String value) {
        setProperty(key, value);
    }
    public String getValue(String key) {
        return getProperty(key, "");
    }
}

/* 解答例コードで出たエラーコード
エラー: シンボルを見つけられません
                load(new FileInputStream(filename));
                ^
  シンボル:   メソッド load(FileInputStream)
  場所: クラス FileProperties

エラー: FileOutputStreamに適切なコンストラクタが
見つかりません(String,String)
                store(new FileOutputStream(filename,
 "written by FileProperties"));
                      ^
    コンストラクタ FileOutputStream.FileOutputStream(String,boolean)は
使用できません
      (引数の不一致: Stringをbooleanに変換できません:)
    コンストラクタ FileOutputStream.FileOutputStream(File,boolean)は
使用できません
      (引数の不一致: StringをFileに変換できません:)
                setProperty(key, value);
                ^
  シンボル:   メソッド setProperty(String,String)
  場所: クラス FileProperties
注意:一部のメッセージは簡略化されています。
-Xdiags:verboseで再コンパイルして完全な出力を取得してください
*/

◇エラーへの対処:FileReader,FileWriterに変更。
ついでにtry-with-resources文に書き換え。参考:独習Java(山田 祥寛(著))

 

第4章 Factory Method

List4-4(IDCardFactory.java)

package idcard;
import framework.*;
import java.util.*;

public class IDCardFactory extends Factory {
    private List<String> owners = new ArrayList<String> ();
    protected Product createProduct(String owner) {
        return new IDCard(owner);
    }
    protected void registerProduct(Product product) {
        owners.add(((IDCard)product).getOwner());
    }
    public List getOwners() {
        return owners;
    }
}

◇エラーへの対処:List⇒List<String>、ArrayList⇒ArrayList<String>に変更。

 

練習問題4-2:ListA4-2(IDCardFactory.java)

package idcard;
import framework.*;
import java.util.*;

public class IDCardFactory extends Factory {
    private HashMap<Integer,String> database = new HashMap<Integer,String>();
    private int serial = 100;

    protected synchronized Product createProduct(String owner) {
        return new IDCard(owner, serial++);
    }
    protected void registerProduct(Product product) {
        IDCard card = (IDCard)product;
        database.put(Integer.valueOf(card.getSerial()), card.getOwner());
    }
    public HashMap getDatabase() {
        return database;
    }
}

◇対処1:HashMap<Integer,String>(); に変更【2箇所】
◇対処2:IntegerはJava9で非推奨⇒Integer.valueOfに変更
◇対処3:Hashtableはエラーが出る⇒HashMapに変更

◇1参考:HashMapクラス| Let’sプログラミング
◇1参考:java.util.HashMap.put() Method

◇2参考:Java9からIntegerとDoubleが非推奨になっていました
◇2参考:Javaのコンパイル時のエラー

 

第8章 Abstract Factory

List8-5(Factory.java)※練習問題8-2も同じ修正が必要

package factory;

public abstract class Factory {
    public static Factory getFactory(String classname) {
        Factory factory = null;
        try {
            factory = (Factory)Class.forName(classname).getDeclaredConstructor().newInstance();
        } catch (ClassNotFoundException e) {
            System.err.println("クラス " + classname + " が見つかりません。");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return factory;
    }
    public abstract Link createLink(String caption, String url);
    public abstract Tray createTray(String caption);
    public abstract Page createPage(String title, String author);
    public Page createYahooPage() {                                     
        Link link = createLink("Yahoo!", "http://www.yahoo.com/");      
        Page page = createPage("Yahoo!", "Yahoo!");                     
        page.add(link);                                                 
        return page;                                                    
    }                                                                   
}

/*  解答例で当初出たエラーコード
注意:.\factory\Factory.javaは推奨されないAPIを使用またはオーバーライドしています。
注意:詳細は、-Xlint:deprecationオプションを指定して再コンパイルしてください。
注意:入力ファイルの操作のうち、未チェックまたは安全ではないものがあります。
注意:詳細は、-Xlint:uncheckedオプションを指定して再コンパイルしてください。
*/

◇対処:Class.newInstance()はJava9で非推奨⇒Class.getDeclaredConstructor().newInstance() に変更

◇参考:Class.newInstance()はJava9から非推奨になるので今から書き方を変えておこう

 


当修正については細かい点で色々突っ込みどころはあると思いますが、なるべく元コードの雰囲気をいじらないように、かつコンパルエラーにはならないように心がけました(自分にとってかなり勉強になりました)。ご参考になれば幸いです。

元のソースコード出典:結城浩「増補改訂版 Java言語で学ぶデザインパターン入門」(2004年)

 





コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

1.日本語が含まれない投稿は無視されますのでご注意ください。(海外からのスパム対策)

2.コメントの非公開を希望される場合は「管理者だけに表示」にチェックを入れてください。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください