1. 程式人生 > >工廠餓漢式單例模式

工廠餓漢式單例模式

先說一下單例模式,單例模式有兩種,一種時懶漢式(有執行緒安全問題),另一種式餓漢式(無執行緒安全問題)。

懶漢式可以通過加鎖解決安全問題,如下兩端程式碼,第一段式有執行緒安全問題的,一年前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();
		}
	}

結果如下