综述
周易是中国传统文化的基石. 涵盖了包括哲学在内的多个学科. 对于周易的理解, 可谓见仁见智. 在最近一个项目中需要使用农历, 并进行简单的五行关系比较. 我上网找了一下, 这方面的资料很多, 道理也不复杂, 但是真正可以使用的类库却完全没有. 所以我打算把自己建立的类库共享出来, 使其他人不需要做相同的重复劳动.
本人并非专门研究周易, 甚至还算不上易学爱好者. 只是在日常生活中偶有接触, 感概于其精妙. 本系列文章与周易等哲学和无直接关系, 这里只是粗浅地使用计算机语言(Java)来对周易中一些概念进行建模, 以其能复用于不同项目中.
太极
周易之中, 万象均始于太极(道生一,一生万物). 故先定义接口太极(Taiji). 由于万象均有其名称及其它属性, 为了便于计算机理解, 这里为万物定义一个值(value)属性,该属性是万物在特定领域的一个特征值. 另外再定义一个属性(name)用于表示对象的标识, 使得人可以易于理解计算机所表达.
/** * <B>Taiji</B> * 太极.万象均循此道. * */ public interface Taiji { public String getName(); public int getValue(); }
/** * <B>AbstractTaiji</B> * 太极的抽象实现*/ public abstract class AbstractTaiji implements Taiji { protected int value; protected String name; protected AbstractTaiji(int value,String name) { this.value = value; this.name = name; } @Override public String getName(){ return name; } @Override public int getValue(){ return value; } @Override public String toString() { return name; } @Override public boolean equals(Object other) { if (other == null) { return false; } if (other instanceof AbstractTaiji) { return ((AbstractTaiji) other).value == value; } return false; } @Override public int hashCode() { return ((Integer)value).hashCode(); } }
易有太极,是生两仪. 有了太极,接下来就要定义两仪.两仪也就是阴阳, <<素问>>曰:" 阴阳者,天地之道也,万物之纲纪,变化之父母". 两仪变化生四象. 四象由两仪变化而来, 为了方便, 这里直接定义四象, 而不单独定义两仪.
/** * <B>FourQuadrant</B> * 四象 */ public class FourQuadrant extends AbstractTaiji{ /** 少阳 */ public static final int SHAO_YANG = 0; /** 少阴*/ public static final int SHAO_YIN = 1; /** 太阳 */ public static final int TAI_YANG = 2; /** 太阴 */ public static final int TAI_YIN = 3; private static final String[] QUADRANT_NAMES=new String[]{ LiuyaoStringSymbol.FourQuadrant_SHAO_YANG, LiuyaoStringSymbol.FourQuadrant_SHAO_YIN, LiuyaoStringSymbol.FourQuadrant_TAI_YANG, LiuyaoStringSymbol.FourQuadrant_TAI_YIN }; public static FourQuadrant getFourQuadrant(int value) { return create(value); } public static FourQuadrant[] getFourQuadrant() { FourQuadrant[] fourQuadrants=new FourQuadrant[4]; for(int i=0;i<4;i++){ fourQuadrants[i] =create(i); } return fourQuadrants; } private static FourQuadrant create(int value) { return new FourQuadrant(value, QUADRANT_NAMES[value%4]); } private FourQuadrant(int v, String name) { super(v, name); } @Override public boolean equals(Object obj) { if (super.equals(obj) && (obj instanceof FourQuadrant)) { return true; } return false; } /** 老阳动化为少阳 */ public FourQuadrant toTwoForms() { if (value == TAI_YANG) { return getFourQuadrant(SHAO_YANG); } else if (value == TAI_YIN){ return getFourQuadrant(SHAO_YIN); } else if (value == SHAO_YANG || value == SHAO_YIN) { return this; } else { return null; } } /** 返回变爻:阳动返回少阴 */ public FourQuadrant getChanged() {//FIXME if(value ==TAI_YANG){ return getFourQuadrant(SHAO_YIN); } if (value == TAI_YIN) { return getFourQuadrant(SHAO_YANG); } return new FourQuadrant(value, name); } /** 动: 阴变阴动;阳变阳动 */ public void activate(){ changeValue(value%2+2); } private void changeValue(int newValue) { this.value=newValue; this.name = QUADRANT_NAMES[newValue]; } /** 阳转为阴,阴转为阳 */ public FourQuadrant reverse() { if(isChanged()){ throw new IllegalArgumentException(); } return getFourQuadrant((value+1)%2); } /** 是否为老阳O 老阴X */ public boolean isChanged() { return (value==TAI_YANG ||value==TAI_YIN); } }
这里为什么不定义为枚举(enum)类?
这主要考虑古人对概念的抽象性过高. 比如阴阳或后面要说的五行, 其字面意义看起来比较简单, 但在现实中,不同领域的应用却又有不同属性. 比如五行在中医里面所代表的事物和天文学甚至预测学中的意义是相差很大的. 我们知道Java的enum类不支持继承,若将这些基本属性定义为枚举类, 会带来一些重复工作. 所以为了简便起见, 这里不使用枚举类.
四象定义好了, 接下来要定义万物了. 万物都离不开道的原始属性, 却又有其自身特有的属性. 万物之间又有各种各样的联系,我们无法一一将其列举.为了简单地表示万物之间的关系, 古人将世间事物分为五种(五行),即金木水火土. 并用五行之间的相生相克的关系来解释事物之间的关系. 五行的定义和四象基本一样, 代码也几乎完全重复, 但这里又不得不将其区分出来.
/** * <B>FiveElements</B> * 五行 */ public class FiveElements extends AbstractTaiji { public static final int GOLD=0; public static final int WATER=1; public static final int WOOD=2; public static final int FIRE=3; public static final int SOIL=4; private static final String[] ELEMENTS_NAMES=new String[]{ LiuyaoStringSymbol.FIVE_ELEMENT_GOLD, LiuyaoStringSymbol.FIVE_ELEMENT_WATER, LiuyaoStringSymbol.FIVE_ELEMENT_WOOD, LiuyaoStringSymbol.FIVE_ELEMENT_FIRE, LiuyaoStringSymbol.FIVE_ELEMENT_SOIL }; public static FiveElements getElement(int value) { return create(value); } private static FiveElements create(int value) { return new FiveElements(value, ELEMENTS_NAMES[value%4]); } /** 相生 */ public static final int Generate = 1<<1; /** 相克 */ public static final int Restricte = 1<<2; private FiveElements(int v, String name) { super(v, name); } /** 生 */ public boolean isGenerate(FiveElements other) { return (value + 1) % 5 == other.value; } /** 克 */ public boolean isRestricte(FiveElements other) { return (value + 2) % 5 == other.value; } }
五行还可以再细分. 比如黄历中使用的五行和周易其它分支使用的五行有所不同, 这时可以按照自己的需要定义五行的具体类. 这里, 如果金木水火土各有其明确且不同的定义,也可以将其作为五行的子类来定义 . 如果具体的五行实现类之间又有复杂的关系, 不推荐将这些关系定义到具体的五行类里面(会使类变得臃肿且难以复用), 这里可以另外定义一个工具类来计算之间的关系. 如下图
五行子类定义示意图
下一篇 天干与地支