首先提一下java的設計原則:php
1.CHANGE (能應對變化)java
2.KISS(keep it simple &studio 保持代碼簡單的易讀性)設計模式
3.DRY(don't repeat youself 不要寫一些重複的代碼)ide
4.SRP(single responsibility principle 單一職責原則)spa
5.OCP(open closed principle 對外開放,對內封閉).net
6.LSP(liskov substitution principle 里氏置換原則)設計
7.ISP(interface single principle 接口隔離原則)代理
8.DIP(dependence Inversion principle 依賴倒置原則)code
固然,還有其餘不少例如:CARP LOD COC ....blog
關於java的設計原則,網上有不少.能夠參考:http://blog.csdn.net/gaolei1201/article/details/47082783
如今,開始要說的是,在什麼樣的場景下使用他們.
案例:輸出三行 hello World
首先,咱們確定想到的是:
public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World"); System.out.println("Hello World"); System.out.println("Hello World"); } }
如今,需求變化了,客戶但願輸出的是三個Hello Java .那麼怎麼辦呢?修改很簡單,直接複製Java粘貼替換World就能夠.可是,這顯然有問題的,若是輸出是10多二十行呢?那不是要複製粘貼而屢次?這時候,能夠把HelloWorld抽取出來,單獨作一個類.該類提供一個方法,返回HelloWorld語帶代碼:
public class HelloWorld { public static void main(String[] args) { System.out.println(new A().getStr()); System.out.println(new A().getStr()); System.out.println(new A().getStr()); } } class A { public String getStr(){ return "Hello World" ; } }
可是,很明顯.客戶有可能要輸出的是Hello Java ,Hello Html ...顯然,每次都須要修改類A,這就違反了以前的開閉原則.那麼怎麼重構呢?能夠這樣:
public class HelloWorld { public static void main(String[] args) { System.out.println(new A().getStr(new Java())); System.out.println(new A().getStr(new World())); System.out.println(new A().getStr(new Html())); } } class A { public String getStr(B b){ return "Hello "+b.getcontent() ; } } abstract class B { public String getcontent() { return setStr() ; } abstract String setStr() ; } class Java extends B{ @Override String setStr() { return "Java"; } } class World extends B { @Override String setStr() { return "World"; } } class Html extends B{ @Override String setStr() { return "Html"; } }
這樣,下次若是須要PHP的時候,只須要擴展類B 而後返回php就好了,不在須要修改源代碼.這裏每次都須要new Java 很明顯,這裏用以前提到的LSP(里氏替換原則),可是又有一個問題,每次調用都須要去寫實例化代碼,這樣代碼顯的比較的臃腫.也違反了以前提到的SRP(單一職責原則)這時候,咱們採用Java設計模式的代理模式,作一個工廠,工廠傳入一個參數.讓工廠來實例化.因而代碼以下:
public class HelloWorld { public static void main(String[] args) { System.out.println(new A().getStr(HelloFactory.getInstance("Java"))); System.out.println(new A().getStr(HelloFactory.getInstance("Html"))); System.out.println(new A().getStr(HelloFactory.getInstance("World"))); } } class A { public String getStr(B b){ return "Hello "+b.getcontent() ; } } abstract class B { public String getcontent() { return setStr() ; } abstract String setStr() ; } class Java extends B{ @Override String setStr() { return "Java"; } } class World extends B { @Override String setStr() { return "World"; } } class Html extends B{ @Override String setStr() { return "Html"; } } class HelloFactory { public static B getInstance(String str){ switch (str) { case "Java": return new Java() ; case "Html": return new Html() ; case "Hello": return new World() ; default : return null ; } } }
可是這樣還有一個問題,若是我要新增一個php,那麼工廠類又要從新寫!很明顯,違反了開閉原則.這時候,咱們能夠採用反射機制來實現,代碼以下:
package test.com; public class HelloWorld { public static void main(String[] args) { try { System.out.println(new A().getStr(HelloFactory.getInstance("Java"))); System.out.println(new A().getStr(HelloFactory.getInstance("Html"))); System.out.println(new A().getStr(HelloFactory.getInstance("World"))); } catch (Exception e) { e.printStackTrace(); } } } class A { public String getStr(B b) { return "Hello " + b.getcontent(); } } abstract class B { public String getcontent() { return setStr(); } abstract String setStr(); } class Java extends B { @Override String setStr() { return "Java"; } } class World extends B { @Override String setStr() { return "World"; } } class Html extends B { @Override String setStr() { return "Html"; } } class HelloFactory { public static B getInstance(String str) throws Exception { // 這裏採用的是包名+類名形式,由於我這個類是在test.com包下. return (B) Class.forName("test.com." + str).newInstance(); } }
如今能夠直接新增一個php的類,而後經過工廠來實例化了.可是,這裏還有一個問題,若是是第三方使用個人方法來輸出Hello World ,那麼每次第三方要新增的時候,我都要去修改個人源代碼...oh,no!!必須重構~~,那麼採用接口方式吧,把控制權給到第三方(使用我代碼開發的人):
package test.com; public class HelloWorld { public static void main(String[] args) { try { System.out.println(new A().getStr(HelloFactory.getInstance("Java"))); System.out.println(new A().getStr(HelloFactory.getInstance("Html"))); System.out.println(new A().getStr(HelloFactory.getInstance("World"))); } catch (Exception e) { e.printStackTrace(); } } } class A { public String getStr(B b) { return "Hello " + b.getcontent(); } } interface B { public String getcontent(); } class Java implements B { public String getcontent() { return "Java"; } } class World implements B { @Override public String getcontent() { return "World"; } } class Html implements B { @Override public String getcontent() { return "Html"; } } class HelloFactory { public static B getInstance(String str) throws Exception { // 這裏採用的是包名+類名形式,由於我這個類是在test.com包下. return (B) Class.forName("test.com." + str).newInstance(); } }
如今,第三方使用個人程序的時候,只須要實現我提供的接口B,就能夠了.再也不依賴我去修改我本身的程序了.可是,若是我要想輸出的是Java Hello,或者就是Html這樣的格式的時候呢? 不是還須要修改個人代碼麼?因此,我必須把更多的控制權給到使用者(第三方).:
package test.com; public class HelloWorld { public static void main(String[] args) { try { System.out.println(HelloFactory.getInstance("Java").getStr(n->{ return n+" Hello" ; })); System.out.println(HelloFactory.getInstance("Html").getStr(n->{ return n+" is too hard" ; })); System.out.println(HelloFactory.getInstance("World").getStr(n->{ return n+" is open" ; })); } catch (Exception e) { e.printStackTrace(); } } } abstract class A { public String getStr(C c) { return c.setStr(getName()) ; } abstract String getName() ; } interface C { public String setStr(String str); } class Html extends A { @Override String getName() { return "Html"; } } class Java extends A { @Override String getName() { return "Java"; } } class World extends A { @Override String getName() { return "World"; } } class HelloFactory { public static A getInstance(String str) throws Exception { // 這裏採用的是包名+類名形式,由於我這個類是在test.com包下. return (A) Class.forName("test.com." + str).newInstance(); } }
這樣,第三方想要什麼格式的都有了.可是這裏還有一個問題,若是我不實用Java,而要使用php的時候,每次都要實現抽象類,而後使用匿名接口,而後再從新編譯.那麼若是作成配置文件,是否是就再也不須要從新編譯了呢?因而能夠改寫:
package test.com; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.InputStream; import java.util.Properties; public class HelloWorld { public static void main(String[] args) { Properties properties = new Properties(); try { InputStream inputStream = new BufferedInputStream(new FileInputStream("src/test/com/mySet.properties")); properties.load(inputStream); System.out.println(HelloFactory.getInstance(properties.getProperty("key1").toString()).getStr(n -> { return n + " Hello"; })); System.out.println(HelloFactory.getInstance(properties.getProperty("key2").toString()).getStr(n -> { return n + " Hello"; })); System.out.println(HelloFactory.getInstance(properties.getProperty("key3").toString()).getStr(n -> { return n + " Hello"; })); } catch (Exception e) { e.printStackTrace(); } } } abstract class A { public String getStr(C c) { return c.setStr(getName()); } abstract String getName(); } interface C { public String setStr(String str); } class Html extends A { @Override String getName() { return "Html"; } } class Java extends A { @Override String getName() { return "Java"; } } class World extends A { @Override String getName() { return "World"; } } class HelloFactory { public static A getInstance(String str) throws Exception { // 這裏採用的是包名+類名形式,由於我這個類是在test.com包下. return (A) Class.forName("test.com." + str).newInstance(); } }
配置文件(mySet.properties):
key1=Java key2=Html key3=World
到這裏,若是第三方想要輸出什麼格式,均可以自由發揮.想要輸出php只需修改配置文件就能夠了.也不須要再對個人代碼驚醒從新編譯.貌似比較完善了..
可是,真的這樣嗎?
如今,寫了這麼多代碼,可是好像我什麼都沒作...要實現什麼樣的輸出,都須要去先實現個人抽象類,而後在修改配置文件.我什麼都沒作啊,貌似.可是,比起最初的版本,我實際確實作了太多的工做,那麼該不應如此作呢?例如客戶只須要輸出一個Hello World,而你卻給我如此一大堆,最還要我本身寫一大堆實現類,配置.就爲了一個Hello World? 確定有病!!
因此,這就是代碼的另外一個原則YAGNI(You Ain’t Gonna Need It 你是否是真的須要它!) 我理解爲中庸,儒家思想嘛.
對於Java思想來講,這只是冰山一角.自我勉勵吧.