Tiny Formater


昨日@Brinがプログラムを書こうとした文章を読みました. 何行かのJavaコード実装の簡単なテンプレート(エンジンではありません)、ほほほ、とても私のポケットを取り出したいと思って、やはり1つの類似のものを発見して、物が小さすぎて、どのように書くつもりはありませんが、@Brinがプログラムを書きたい文章を見て、考えても文章を出して、その時の私の考えと考えを話します.
文字列を変換するフォーマットプロバイダ:
public interface FormatProvider {
	/**
	 *             
	 * 
	 * @param string
	 *                    
	 * @return       
	 * @throws FormatException
	 */
	String format(Context context, String string) throws FormatException;

}

インタフェースメソッドは1つだけで、入力には2つのパラメータがあります.1つはコンテキストで、1つはフォーマットを行う列で、返される値はフォーマット処理された列です.
もちろん、いくつかの列が私たちのポイント記号と衝突する可能性があるのではないかと心配しています.そのため、ユーザーが自分でポイント記号を指定することを期待しています.そのため、次のインタフェースが設定されています.
/**
 *         
 * 
 * @author luoguo
 * 
 */
public interface PatternDefine {
	/**
	 *       
	 * 
	 * @return
	 */
	Pattern getPattern();

	/**
	 *     
	 * 
	 * @param prefixPatternString
	 */
	void setPrefixPatternString(String prefixPatternString);

	/**
	 *     
	 * 
	 * @param postfixPatternString
	 */
	void setPostfixPatternString(String postfixPatternString);

	/**
	 *            
	 * 
	 * @param patternString
	 */
	void setPatternString(String patternString);

	/**
	 *       
	 * 
	 * @param string
	 * @return
	 */
	String getPureMatchText(String string);

	/**
	 *           
	 * 
	 * @param string
	 * @return
	 */
	String getFullMatchText(String string);

	/**
	 *       
	 * 
	 * @return
	 */
	void setSplitChar(char splitChar);

	/**
	 *      
	 * 
	 * @return
	 */
	char getSplitChar();
}

もちろん上のインタフェースが1つ固定されていれば、フレーム内部はすでに提供されており、別途拡張する必要はありません.
フォーマットインタフェースは次のとおりです.
/**
 *       
 * 
 * @author luoguo
 * 
 */
public interface Formater extends FormatProvider {

	/**
	 *        ,            ,           
	 * 
	 * @param patternHandle
	 */
	void setPatternHandle(PatternDefine patternHandle);

	/**
	 *         
	 * 
	 * @param formatProviders
	 *            Key      
	 */
	void setFormatProviders(Map<String, FormatProvider> formatProviders);

	/**
	 *         
	 * @param prefix   
	 * @param formatProvider
	 */
	void addFormatProvider(String prefix, FormatProvider formatProvider);
}

3つの方法で setPatternHandleはフォーマットセッションモードを設定するために使用され、setFormatProvidersはフォーマットプロバイダを設定するために使用されます.mapであるため、key値は接頭辞であり、valueは対応するフォーマットプロセッサです.もちろんaddFormatProviderで一つ一つ増やしていくこともできます.
はい、インタフェースの件は終わりました.具体的な実装クラスを見てみましょう.
デフォルトのフォーマット実装クラス:
public class DefaultPatternDefine implements PatternDefine {

	private static final String DEFAULT_PATTERN_STRING = "([$]+[{]+[a-zA-Z0-9[.[_[:[/[#]]]]]]+[}])";
	private static final String DEFAULT_POSTFIX_PATTERN_STRING = "}";
	private static final String DEFAULT_PREFIX_PATTERN_STRING = "${";
	private static final char DEFAULT_SPLIT_CHAR = ':';
	private String prefixPatternString = DEFAULT_PREFIX_PATTERN_STRING;//   
	private String postfixPatternString = DEFAULT_POSTFIX_PATTERN_STRING;//   
	private String patternString = DEFAULT_PATTERN_STRING;//     
	private Pattern pattern;
	private char splitChar = DEFAULT_SPLIT_CHAR;//     

	public Pattern getPattern() {
		if (pattern == null) {
			pattern = Pattern.compile(patternString);
		}
		return pattern;
	}

	public void setPrefixPatternString(String prefixPatternString) {
		this.prefixPatternString = prefixPatternString;
	}

	public void setPostfixPatternString(String postfixPatternString) {
		this.postfixPatternString = postfixPatternString;
	}

	public void setPatternString(String patternString) {
		this.patternString = patternString;
	}

	public String getPureMatchText(String string) {
		int startPos = prefixPatternString.length();
		int endPos = string.length() - postfixPatternString.length();
		return string.substring(startPos, endPos);
	}

	public String getFullMatchText(String string) {
		return String.format("%s%s%s", prefixPatternString, string,
				postfixPatternString);
	}

	public void setSplitChar(char splitChar) {
		this.splitChar = splitChar;
	}

	public char getSplitChar() {
		return splitChar;
	}

}

次はContext用のフォーマット列です.
public class ContextFormater implements FormatProvider {

	public String format(Context context, String string) throws FormatException {
		Object obj = context.get(string);
		if (obj != null) {
			return obj.toString();
		}
		int index = string.indexOf('.');
		if (index > 0) {
			String name = string.substring(0, index);
			obj = context.get(name);
			if (obj != null) {
				String property = string.substring(index + 1);
				try {
					return BeanUtils.getProperty(obj, property).toString();
				} catch (Exception e) {
					throw new FormatException(e);
				}
			}
		}
		return null;
	}
}

次はコアのフォーマットアルゴリズムです.
public class FormaterImpl implements Formater {

	private Map<String, FormatProvider> formatProviders;
	private PatternDefine patternDefine = new DefaultPatternDefine();

	/**
	 *                
	 */
	public FormaterImpl() {
	}

	/**
	 *         ,      ,       ,     
	 * 
	 * @throws FormatException
	 */
	public String format(Context context, String source) throws FormatException {
		Matcher matcher = patternDefine.getPattern().matcher(source);
		StringBuffer buf = new StringBuffer();
		int curpos = 0;
		while (matcher.find()) {
			String replaceStr = patternDefine.getPureMatchText(matcher.group());
			buf.append(source.substring(curpos, matcher.start()));
			curpos = matcher.end();
			String str = formatSingle(context, replaceStr);
			if (str != null) {
				buf.append(str);
			}
			continue;
		}
		buf.append(source.substring(curpos));
		return buf.toString();
	}

	/**
	 *       
	 * 
	 * @param string
	 *            String
	 * @return String
	 * @throws FormatException
	 * @throws Exception
	 */
	private String formatSingle(Context context, String string)
			throws FormatException {
		String s[] = string.split(patternDefine.getSplitChar() + "");
		if (s.length >= 2) {
			FormatProvider o = (FormatProvider) formatProviders.get(s[0]);
			if (o != null) {
				return o.format(context, s[1]);
			}
		} else {
			FormatProvider o = (FormatProvider) formatProviders.get("");
			if (o != null) {
				return o.format(context, string);
			}
		}
		return patternDefine.getFullMatchText(string);
	}

	public void setFormatProviders(Map<String, FormatProvider> formatProviders) {
		this.formatProviders = formatProviders;
	}

	public void setPatternHandle(PatternDefine patternHandle) {
		this.patternDefine = patternHandle;

	}

	public void addFormatProvider(String prefix, FormatProvider formatProvider) {
		if (formatProviders == null) {
			formatProviders = new HashMap<String, FormatProvider>();
		}
		formatProviders.put(prefix, formatProvider);
	}

}

重要ではないので、ここでは説明しません.次に例を見てみましょう.
定数フォーマットプロバイダを追加するには、次の手順に従います.
public class ConstFormatProvider implements FormatProvider {
	Map<String, String> constMap = new HashMap<String, String>();

	public String format(Context context, String key) {
		return constMap.get(key);
	}

	public Map<String, String> getConstMap() {
		return constMap;
	}

	public void setConstMap(Map<String, String> constMap) {
		this.constMap = constMap;
	}

}

日付フォーマットプロバイダをもう1つ追加:
public class DateFormatProvider implements FormatProvider {
	Map<String, String> constMap = new HashMap<String, String>();

	public String format(Context context, String key) {
		return constMap.get(key);
	}

	public Map<String, String> getConstMap() {
		return constMap;
	}

	public void setConstMap(Map<String, String> constMap) {
		this.constMap = constMap;
	}

}

テスト用のPOJOクラスをもう一つ追加します.
public class User {
	String name;
	int age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public User() {

	}

	public User(String name, int age) {
		this.name = name;
		this.age = age;
	}
}

はい、認めます.前はマットを作って、竜のカバーを走っています.本当のショーの下から始まります.
/**
	 *            
	 * 
	 * @throws FormatException
	 */
	public void testFormatNotPlaceholder() throws FormatException {
		assertEquals("this is test", formater.format(context, "this is test"));
	}

	/**
	 *       ,            
	 * 
	 * @throws FormatException
	 */
	public void testFormatExistPlaceholderProvider() throws FormatException {
		Context context = new ContextImpl();
		assertEquals("this is v1 test",
				formater.format(context, "this is ${const:1} test"));
	}

	/**
	 *       ,             
	 * 
	 * @throws FormatException
	 */

	public void testFormatExistPlaceholderNoProvider() throws FormatException {
		assertEquals("this is ${abc:2} test",
				formater.format(context, "this is ${abc:2} test"));
	}

	/**
	 *       ,  bean   
	 * 
	 * @throws FormatException
	 */

	public void testFormatBean() throws FormatException {
		User user = new User("aa", 123);
		context.put("user", user);
		assertEquals("this is aa test 123",
				formater.format(context, "this is ${context:user.name} test ${context:user.age}"));

	}

以下にまとめる.
上のフォーマットプレースホルダ方式は${...}方式であり、中間の...はaa:bbの方式であってもよいし、直接bbの方式であってもよい.これにより、開発者がフォーマットプロセッサの処理能力を絶えず拡張することができます.プレースホルダマッチングも拡張可能であるため,独自のフォーマットプレースホルダ方式を独自に定義することができる.
オブジェクトのプロパティは無限に下に下がることができます.もちろん、配列など、他の処理方法を追加することもできます.
だから機能や位置づけから言えば、@Brinがプログラムを書きたいのと同じです.
ネタバレ:当時私はテンプレート言語を書きたかったのですが、直接Velocityを多重化することにしたので、ここまでです.
あきらめたが、その中の設計と基礎構造の面でのいくつかの思想とモデルは、学生たちの参考と参考に値する.