工廠餓漢式單例模式
阿新 • • 發佈:2018-11-05
先說一下單例模式,單例模式有兩種,一種時懶漢式(有執行緒安全問題),另一種式餓漢式(無執行緒安全問題)。
懶漢式可以通過加鎖解決安全問題,如下兩端程式碼,第一段式有執行緒安全問題的,一年前lz去面試被要求手寫單例模式的時候就是這樣寫的,被面試官狠狠的鄙視了一波。
package test; /** * @author mzl * */ public class Singleton { private static Singleton instance=null; private Singleton(){ } public static Singleton getInstance(){ if(instance==null){ instance=new Singleton(); } return instance; } }
經過面試官指正後,加鎖
public class Singleton { private static Singleton instance=null; private Singleton(){ } public static Singleton getInstance(){ if(instance==null){ synchronized(Singleton.class){ if(instance==null){ instance=new Singleton(); } } } return instance; } }
接下來把單例用到工廠模式式去,比如我們工廠模式要生產one、tow、three三個物件,我們可以定義一個介面,讓它們都實現這個介面,同時為了程式碼更容易維護,使用註解方式,來標記以上三個類。
一、定義一個介面
public interface Strategy {
public String str1(int id1,int id2);
public String str2();
}
二、自定義一個註解
@Retention(value = RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Pay { int channlId(); }
@Reteniton的作用是定義被它所註解的註解保留多久,一共有三種策略,定義在RetentionPolicy列舉中
-
SOURCE
被編譯器忽略 -
CLASS
註解將會被保留在Class檔案中,但在執行時並不會被VM保留。這是預設行為,所有沒有用Retention註解的註解,都會採用這種策略。 -
RUNTIME
@Target表示作用什麼地方。
-
保留 1.CONSTRUCTOR:用於描述構造器
2.FIELD:用於描述域
3.LOCAL_VARIABLE:用於描述區域性變數
4.METHOD:用於描述方法
5.PACKAGE:用於描述包
6.PARAMETER:用於描述引數
7.TYPE:用於描述類、介面(包括註解型別) 或enum宣告至執行時。所以我們可以通過反射去獲取註解資訊。
三、one、tow、three三個類程式碼如下
@Pay(channlId = 1)
public class One implements Strategy{
@Override
public String str1(int id1, int id2) {
return null;
}
@Override
public String str2() {
return "one";
}
}
@Pay(channlId = 3)
public class Two implements Strategy{
@Override
public String str1(int id1, int id2) {
return null;
}
@Override
public String str2() {
return "two";
}
}
@Pay(channlId = 2)
public class Three implements Strategy{
@Override
public String str1(int id1, int id2) {
return null;
}
@Override
public String str2() {
return "three";
}
}
四、市場工廠單例模式去生成以上三個類
public class TestFactory {
private TestFactory() {
}
//餓漢式
private static class SingletonTest{
private final static TestFactory testFactory=new TestFactory();
}
public static TestFactory getTestFactory(){
return SingletonTest.testFactory;
}
//存放class路徑
public static Map<Integer,String> map=new HashMap<Integer, String>();
static{
//通過註解,把map自動維護
Reflections reflections=new Reflections("testsunmet.imp.*");
//獲取有Pay註解的class
Set<Class<?>> classes=reflections.getTypesAnnotatedWith(Pay.class);
for(Class<?> cl:classes){
Pay pay=cl.getAnnotation(Pay.class);
map.put(pay.channlId(), cl.getCanonicalName());
}
}
//具體生產方法
public Strategy create(Integer id) throws Exception{
String clazz=map.get(id);
Class clazz2=Class.forName(clazz);
return (Strategy) clazz2.newInstance();
}
}
五、測試看看生成出來的物件
public class TestMain {
public static void main(String arg[]){
try {
Strategy one=TestFactory.getTestFactory().create(1);
System.out.println("這是"+one.str2());
Strategy two=TestFactory.getTestFactory().create(2);
System.out.println("這是"+two.str2());
Strategy three=TestFactory.getTestFactory().create(3);
System.out.println("這是"+three.str2());
} catch (Exception e) {
e.printStackTrace();
}
}
結果如下