設計モデル——工場モデルの開発における応用(簡易計算機)


簡単な計算機を例に、ファクトリモードの使い方を説明します.
デザインモードを使用していない場合は、次のように書く可能性があります.
package com.meritit;

import java.util.Scanner;

public class MainClass {
	public static void main(String[] args) {
		double result = 0;
		//1.       
		System.out.println("-----     -----");
		System.out.println("        ");
		Scanner scan = new Scanner(System.in);
		String strNum1 = scan.nextLine();
		
		System.out.println("     ");
		String oper = scan.nextLine();
		
		System.out.println("        ");
		String strNum2 = scan.nextLine();
		//2.    
		if("+".equals(oper)){
			result = Double.parseDouble(strNum1) + Double.parseDouble(strNum2);
		}else if("-".equals(oper)){
			result = Double.parseDouble(strNum1) - Double.parseDouble(strNum2);
		}else if("*".equals(oper)){
			result = Double.parseDouble(strNum1) * Double.parseDouble(strNum2);
		}else if("/".equals(oper)){
			result = Double.parseDouble(strNum1) / Double.parseDouble(strNum2);
		}
		//3.    
		System.out.println(strNum1 + oper + strNum2 + "=" + result);
	}
}

このように判断演算子に書くコードの繰返し率が高すぎる
次のように書くことができます.
(1)抽象的な計算クラス
package com.meritit;

public abstract class Operation {
	private double num1;
	private double num2;
	public double getNum1() {
		return num1;
	}
	public void setNum1(double num1) {
		this.num1 = num1;
	}
	public double getNum2() {
		return num2;
	}
	public void setNum2(double num2) {
		this.num2 = num2;
	}
	public abstract double getResult();
}
(2)具体的な加算実装クラス
package com.meritit;

public class AddOperation extends Operation{

	@Override
	public double getResult() {
		double result = this.getNum1() + this.getNum2();
		return result;
	}

}

(3)主関数は現在このように書くことができる
package com.meritit;

import java.util.Scanner;

public class MainClass {
	public static void main(String[] args) {
		double result = 0;
		//1.       
		System.out.println("-----     -----");
		System.out.println("        ");
		Scanner scan = new Scanner(System.in);
		String strNum1 = scan.nextLine();
		
		System.out.println("     ");
		String oper = scan.nextLine();
		
		System.out.println("        ");
		String strNum2 = scan.nextLine();
		double num1 = Double.parseDouble(strNum1);
		double num2 = Double.parseDouble(strNum2);
		//2.    
		if("+".equals(oper)){
			Operation operation = new AddOperation();
			operation.setNum1(num1);
			operation.setNum2(num2);
			result = operation.getResult();
		}else if("-".equals(oper)){
			result = Double.parseDouble(strNum1) - Double.parseDouble(strNum2);
		}else if("*".equals(oper)){
			result = Double.parseDouble(strNum1) * Double.parseDouble(strNum2);
		}else if("/".equals(oper)){
			result = Double.parseDouble(strNum1) / Double.parseDouble(strNum2);
		}
		//3.    
		System.out.println(strNum1 + oper + strNum2 + "=" + result);
	}
}

しかし,上記の方法はやはり問題があり,演算のたびに操作のクラス名を知り,newオブジェクトによってインスタンス化する.
簡単な工場モデルで実現します.
(1)OperationFactoryファクトリクラスを作成する(まず「+」演算を書く)
package com.meritit;

public class OperationFactory {
	public static Operation getOperation(String oper){
		if("+".equals(oper)){
			return new AddOperation();
		}else{
			return null;
		}
	}
}
(2)現在の主関数にはこのように書くことができます.
package com.meritit;

import java.util.Scanner;

public class MainClass {
	public static void main(String[] args) {
		double result = 0;
		//1.       
		System.out.println("-----     -----");
		System.out.println("        ");
		Scanner scan = new Scanner(System.in);
		String strNum1 = scan.nextLine();
		
		System.out.println("     ");
		String oper = scan.nextLine();
		
		System.out.println("        ");
		String strNum2 = scan.nextLine();
		double num1 = Double.parseDouble(strNum1);
		double num2 = Double.parseDouble(strNum2);
		//2.    
		Operation operation = OperationFactory.getOperation(oper);
		operation.setNum1(num1);
		operation.setNum2(num2);
		result = operation.getResult();
		//3.    
		System.out.println(strNum1 + oper + strNum2 + "=" + result);
	}
}

これにより演算を拡張できるが,工場メソッドの内容を変更し,外部は開放的であるが,内部は閉鎖的ではない.
私たちは今、工場方法モデルで実現しています.
(1)抽象工場の設立方法
package com.meritit;

public interface OperationFactory {
	public Operation getOperation();
}

(2)Add(加算)ファクトリメソッド抽象ファクトリメソッドインタフェースの実現
package com.meritit;

public class AddOperationFactory implements OperationFactory{

	@Override
	public Operation getOperation() {
		return new AddOperation();
	}

}

(3)MainClassではこう書いてあります
package com.meritit;

import java.util.Scanner;

public class MainClass {
	public static void main(String[] args) {
		double result = 0;
		//1.       
		System.out.println("-----     -----");
		System.out.println("        ");
		Scanner scan = new Scanner(System.in);
		String strNum1 = scan.nextLine();
		
		System.out.println("     ");
		String oper = scan.nextLine();
		
		System.out.println("        ");
		String strNum2 = scan.nextLine();
		double num1 = Double.parseDouble(strNum1);
		double num2 = Double.parseDouble(strNum2);
		//2.    
		if("+".equals(oper)){
			OperationFactory oFactory = new AddOperationFactory();
			Operation operation = oFactory.getOperation();
			operation.setNum1(num1);
			operation.setNum2(num2);
			result = operation.getResult();
		}
		//3.    
		System.out.println(strNum1 + oper + strNum2 + "=" + result);
	}
}

このように書くメリットは、演算を増やす(演算記号を増やす)場合、OperationやOperationFactoryを修正する必要がなく、対応する
XxxxOperationとXxxxOperationFactoryで良いのですが、このように書くとMainClassで演算子の判読も行われます.
反射技術を使用してカプセル化します.
(1)プロファイルoperationを書く.properties
          + = com.meritit.AddOperation
(2)構成情報を読み取るツールクラスを書く
package com.meritit;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class ConfigUtil {
	public static String getConfig(String style){
		Properties pro = new Properties();
		InputStream inStream = ConfigUtil.class.getClassLoader().getResourceAsStream("operation.properties");
		try {
			pro.load(inStream);
		} catch (IOException e) {

			e.printStackTrace();
		}
		return pro.getProperty(style);
	}
	
	public static void main(String[] args) {
		System.out.println(getConfig("+"));
	}
}

(3)AddOperationFactoryにこう書く
package com.meritit;

public class AddOperationFactory implements OperationFactory{

	@Override
	public Operation getOperation(String oper)throws Exception{
		String type = ConfigUtil.getConfig(oper);	
		return (Operation)Class.forName(type).newInstance();
	}

}

(4)MainClass判断演算子は不要
package com.meritit;

import java.util.Scanner;

public class MainClass {
	public static void main(String[] args) {
		double result = 0;
		//1.       
		System.out.println("-----     -----");
		System.out.println("        ");
		Scanner scan = new Scanner(System.in);
		String strNum1 = scan.nextLine();
		
		System.out.println("     ");
		String oper = scan.nextLine();
		
		System.out.println("        ");
		String strNum2 = scan.nextLine();
		double num1 = Double.parseDouble(strNum1);
		double num2 = Double.parseDouble(strNum2);
		//2.    
		try {
			OperationFactory oFactory = new AddOperationFactory();
			Operation operation = oFactory.getOperation(oper);
			operation.setNum1(num1);
			operation.setNum2(num2);
			result = operation.getResult();
		} catch (Exception e) {
			e.printStackTrace();
		}

		//3.    
		System.out.println(strNum1 + oper + strNum2 + "=" + result);
	}
}

これでファクトリメソッドモードを使用して簡単な計算機を完成しました.何か問題があれば指摘してください.
ソースのダウンロード:http://download.csdn.net/detail/lxq_xsyu/5907383