這個應該比較簡單一點。
創(chuàng)新互聯(lián)公司是網(wǎng)站建設技術企業(yè),為成都企業(yè)提供專業(yè)的成都做網(wǎng)站、網(wǎng)站制作,網(wǎng)站設計,網(wǎng)站制作,網(wǎng)站改版等技術服務。擁有十多年豐富建站經(jīng)驗和眾多成功案例,為您定制適合企業(yè)的網(wǎng)站。十多年品質,值得信賴!
某系統(tǒng)日志記錄器要求支持多種日志記錄方式,如文件記錄、數(shù)據(jù)庫記錄等,且用戶可以根據(jù)要求動態(tài)選擇日志記錄方式。現(xiàn)使用工廠方法模式設計該系統(tǒng),并寫出相應Java代碼。
interface Log{
public void writeLog();
}
class FileLog implements Log{
public void writeLog(){
System.out.println("文件記錄");
}
}
class DatabaseLog implements Log{
public void writeLog(){
System.out.println("數(shù)據(jù)庫記錄");
}
}
interface LogFactory{
public Log createLog();
}
class FileLogFactory implements LogFactory{
public Log createLog(){
return new FileLog();
}
}
class DatabaseLogFactory implements LogFactory{
public Log createLog(){
return new DatabaseLog();
}
}
public class Client{
public static void main(String[] args) {
try{
Log log;
LogFactory factory;
//這里可以改成使用DOM和Java反射機制讀取XML文件,獲取工廠類名
factory=new DatabaseLogFactory ();
log=factory.createLog();
log.writeLog();
}
catch(Exception e){
System.out.println(e.getMessage());
}
}
}
public class Message {
public static void main(String[] args){
String name;
int age;
System.out.println("請輸入姓名,回車結束:"); //提示輸入
Scanner sc = new Scanner(System.in);
name = sc.nextLine(); //為變量賦值
System.out.println("請輸入年齡,回車結束:");
age = sc.nextInt();
System.out.println("姓名:"+name+"\n年齡:"+age); //打印姓名及年齡
}
}
//不知道這樣行么?
我從我的博客里把我的文章粘貼過來吧,對于單例模式模式應該有比較清楚的解釋:
單例模式在我們日常的項目中十分常見,當我們在項目中需要一個這樣的一個對象,這個對象在內存中只能有一個實例,這時我們就需要用到單例。
一般說來,單例模式通常有以下幾種:
1.饑漢式單例
public class Singleton {
private Singleton(){};
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
這是最簡單的單例,這種單例最常見,也很可靠!它有個唯一的缺點就是無法完成延遲加載——即當系統(tǒng)還沒有用到此單例時,單例就會被加載到內存中。
在這里我們可以做個這樣的測試:
將上述代碼修改為:
public class Singleton {
private Singleton(){
System.out.println("createSingleton");
};
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
public static void testSingleton(){
System.out.println("CreateString");
}
}
而我們在另外一個測試類中對它進行測試(本例所有測試都通過Junit進行測試)
public class TestSingleton {
@Test
public void test(){
Singleton.testSingleton();
}
}
輸出結果:
createSingleton
CreateString
我們可以注意到,在這個單例中,即使我們沒有使用單例類,它還是被創(chuàng)建出來了,這當然是我們所不愿意看到的,所以也就有了以下一種單例。
2.懶漢式單例
public class Singleton1 {
private Singleton1(){
System.out.println("createSingleton");
}
private static Singleton1 instance = null;
public static synchronized Singleton1 getInstance(){
return instance==null?new Singleton1():instance;
}
public static void testSingleton(){
System.out.println("CreateString");
}
}
上面的單例獲取實例時,是需要加上同步的,如果不加上同步,在多線程的環(huán)境中,當線程1完成新建單例操作,而在完成賦值操作之前,線程2就可能判
斷instance為空,此時,線程2也將啟動新建單例的操作,那么多個就出現(xiàn)了多個實例被新建,也就違反了我們使用單例模式的初衷了。
我們在這里也通過一個測試類,對它進行測試,最后面輸出是
CreateString
可以看出,在未使用到單例類時,單例類并不會加載到內存中,只有我們需要使用到他的時候,才會進行實例化。
這種單例解決了單例的延遲加載,但是由于引入了同步的關鍵字,因此在多線程的環(huán)境下,所需的消耗的時間要遠遠大于第一種單例。我們可以通過一段測試代碼來說明這個問題。
public class TestSingleton {
@Test
public void test(){
long beginTime1 = System.currentTimeMillis();
for(int i=0;i100000;i++){
Singleton.getInstance();
}
System.out.println("單例1花費時間:"+(System.currentTimeMillis()-beginTime1));
long beginTime2 = System.currentTimeMillis();
for(int i=0;i100000;i++){
Singleton1.getInstance();
}
System.out.println("單例2花費時間:"+(System.currentTimeMillis()-beginTime2));
}
}
最后輸出的是:
單例1花費時間:0
單例2花費時間:10
可以看到,使用第一種單例耗時0ms,第二種單例耗時10ms,性能上存在明顯的差異。為了使用延遲加載的功能,而導致單例的性能上存在明顯差異,
是不是會得不償失呢?是否可以找到一種更好的解決的辦法呢?既可以解決延遲加載,又不至于性能損耗過多,所以,也就有了第三種單例:
3.內部類托管單例
public class Singleton2 {
private Singleton2(){}
private static class SingletonHolder{
private static Singleton2 instance=new Singleton2();
}
private static Singleton2 getInstance(){
return SingletonHolder.instance;
}
}
在這個單例中,我們通過靜態(tài)內部類來托管單例,當這個單例被加載時,不會初始化單例類,只有當getInstance方法被調用的時候,才會去加載
SingletonHolder,從而才會去初始化instance。并且,單例的加載是在內部類的加載的時候完成的,所以天生對線程友好,而且也不需要
synchnoized關鍵字,可以說是兼具了以上的兩個優(yōu)點。
4.總結
一般來說,上述的單例已經(jīng)基本可以保證在一個系統(tǒng)中只會存在一個實例了,但是,仍然可能會有其他的情況,導致系統(tǒng)生成多個單例,請看以下情況:
public class Singleton3 implements Serializable{
private Singleton3(){}
private static class SingletonHolder{
private static Singleton3 instance = new Singleton3();
}
public static Singleton3 getInstance(){
return SingletonHolder.instance;
}
}
通過一段代碼來測試:
@Test
public void test() throws Exception{
Singleton3 s1 = null;
Singleton3 s2 = Singleton3.getInstance();
//1.將實例串行話到文件
FileOutputStream fos = new FileOutputStream("singleton.txt");
ObjectOutputStream oos =new ObjectOutputStream(fos);
oos.writeObject(s2);
oos.flush();
oos.close();
//2.從文件中讀取出單例
FileInputStream fis = new FileInputStream("singleton.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
s1 = (Singleton3) ois.readObject();
if(s1==s2){
System.out.println("同一個實例");
}else{
System.out.println("不是同一個實例");
}
}
輸出:
不是同一個實例
可以看到當我們把單例反序列化后,生成了多個不同的單例類,此時,我們必須在原來的代碼中加入readResolve()函數(shù),來阻止它生成新的單例
public class Singleton3 implements Serializable{
private Singleton3(){}
private static class SingletonHolder{
private static Singleton3 instance = new Singleton3();
}
public static Singleton3 getInstance(){
return SingletonHolder.instance;
}
//阻止生成新的實例
public Object readResolve(){
return SingletonHolder.instance;
}
}
再次測試時,就可以發(fā)現(xiàn)他們生成的是同一個實例了。
盡量使用完整的英文描述符,采用適用于相關領域的術語,采用大小寫混合使名字可讀。
JAVA代碼規(guī)范:
(1)類名首字母應該大寫。字段、方法以及對象(句柄)的首字母應小寫。對于所有標識符,其中包含的所有單詞都應緊靠在一起,而且大寫中間單詞的首字母。例如:
ThisIsAClassName
thisIsMethodOrFieldName
若在定義中出現(xiàn)了常數(shù)初始化字符,則大寫static final基本類型標識符中的所有字母。這樣便可標志出它們屬于編譯期的常數(shù)。Java包(Package)屬于一種特殊情況:它們全都是小寫字母,即便中間的單詞亦是如此。對于域名擴展名稱,如com,org,net或者edu等,全部都應小寫(這也是Java1.1和Java1.2的區(qū)別之一)。
(2)為了常規(guī)用途而創(chuàng)建一個類時,請采取"經(jīng)典形式",并包含對下述元素的定義:equals()
hashCode()
toString()
clone()(implement Cloneable)
implement Serializable
(3)對于自己創(chuàng)建的每一個類,都考慮置入一個main(),其中包含了用于測試那個類的代碼。為使用一個項目中的類,我們沒必要刪除測試代碼。若進行了任何形式的改動,可方便地返回測試。這些代碼也可作為如何使用類的一個示例使用。
(4)應將方法設計成簡要的、功能性單元,用它描述和實現(xiàn)一個不連續(xù)的類接口部分。理想情況下,方法應簡明扼要。若長度很大,可考慮通過某種方式將其分割成較短的幾個方法。這樣做也便于類內代碼的重復使用(有些時候,方法必須非常大,但它們仍應只做同樣的一件事情)。
(5)設計一個類時,請設身處地為客戶程序員考慮一下(類的使用方法應該是非常明確的)。然后,再設身處地為管理代碼的人考慮一下(預計有可能進行哪些形式的修改,想想用什么方法可把它們變得更簡單)。
(6)使類盡可能短小精悍,而且只解決一個特定的問題。下面是對類設計的一些建議:
一個復雜的開關語句:考慮采用"多形"機制
數(shù)量眾多的方法涉及到類型差別極大的操作:考慮用幾個類來分別實現(xiàn)
許多成員變量在特征上有很大的差別:考慮使用幾個類
(7)讓一切東西都盡可能地"私有"-private??墒箮斓哪骋徊糠?公共化"(一個方法、類或者一個字段等等),就永遠不能把它拿出。若強行拿出,就可能破壞其他人現(xiàn)有的代碼,使他們不得不重新編寫和設計。若只公布自己必須公布的,就可放心大膽地改變其他任何東西。在多線程環(huán)境中,隱私是特別重要的一個因素-只有private字段才能在非同步使用的情況下受到保護。
(8)謹惕"巨大對象綜合癥。對一些習慣于順序編程思維、且初涉OOP領域的新手,往往喜歡先寫一個順序執(zhí)行的程序,再把它嵌入一個或兩個巨大的對象里。根據(jù)編程原理,對象表達的應該是應用程序的概念。
importjava.awt.*;importjava.awt.event.*;classShopFrameextendsFrameimplementsActionListener{Labellabel1,label2,label3,label4;Buttonbutton1,button2,button3,button4,button5;TextAreatext;Panelpanel1,panel2;staticfloatsum=0.0f;ShopFrame(Strings){super(s);setLayout(newBorderLayout());label1=newLabel("面紙:3元",Label.LEFT);label2=newLabel("鋼筆:5元",Label.LEFT);label3=newLabel("書:10元",Label.LEFT);label4=newLabel("襪子:8元",Label.LEFT);button1=newButton("加入購物車");button2=newButton("加入購物車");button3=newButton("加入購物車");button4=newButton("加入購物車");button5=newButton("查看購物車");text=newTextArea("商品有:"+"\n",5,10);text.setEditable(false);addWindowListener(newWindowAdapter(){publicvoidwindowClosing(WindowEvente){System.exit(0);}});button1.addActionListener(this);button2.addActionListener(this);button3.addActionListener(this);button4.addActionListener(this);button5.addActionListener(this);panel1=newPanel();panel2=newPanel();panel1.add(label1);panel1.add(button1);panel1.add(label2);panel1.add(button2);panel1.add(label3);panel1.add(button3);panel1.add(label4);panel1.add(button4);panel2.setLayout(newBorderLayout());panel2.add(button5,BorderLayout.NORTH);panel2.add(text,BorderLayout.SOUTH);this.add(panel1,BorderLayout.CENTER);this.add(panel2,BorderLayout.SOUTH);setBounds(100,100,350,250);setVisible(true);validate();}publicvoidactionPerformed(ActionEvente){if(e.getSource()==button1){text.append("一個面紙、");sum=sum+3;}elseif(e.getSource()==button2){text.append("一只鋼筆、");sum=sum+5;}elseif(e.getSource()==button3){text.append("一本書、");sum=sum+10;}elseif(e.getSource()==button4){text.append("一雙襪子、");sum=sum+8;}elseif(e.getSource()==button5){text.append("\n"+"總價為:"+"\n"+sum);}}}publicclassShopping{publicstaticvoidmain(String[]args){newShopFrame("購物車");}}我沒用Swing可能顯示不出來你的效果。不滿意得話我在給你編一個。