首先提一下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思想来讲,这只是冰山一角.自我勉励吧.