1. 請在草稿紙上手寫一個單例模式的實現代碼,拍照提交作業。
說明:筆者拍照實現餓漢式單例類,也就是應用一啓動,就會把單例對象加載到內存。
問什麼要試用 Singleton
Singleton 模式保證產生單一實例,就是說一個類只產生一個實例。試用 Singleton 有兩個原因
- 是因爲只有一個實例,可以減少實例頻繁創建和銷燬帶來的資源消耗。
- 是當多個用戶試用這個實例的時候,便於進行統一控制(比如打印機對象)。
前者是性能需求,後者是功能需求。
餓漢式 Singleton
public class HungrySingleton {
private static HungrySingleton instance = new HungrySingleton();
private HungrySingleton() {
}
public static HungrySingleton getInstance() {
return instance;
}
}
注意:一定要有私有的構造函數,保證實例只能通過getInstance()
方法獲得。
儘量使用餓漢式構造單實例。單例中的成員變量是多線程重用的,可能會產生意想不到的結果,因此儘量將單例設計爲無狀態對象(只提供服務,不保存狀態)。
餓漢式 Singleton 的問題是,應用一啓動就加載對象進內存,就算從來未被用過。
懶漢式 Singleton
publci class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() {
}
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
注意: getInstance()
的修飾符 synchronized
一定要加上,否則可能會產生多重實例。
懶漢式Singleton解決了餓漢式Singleton,當調用的時候纔去加載對象到內存。但是引發了另外一個性能問題,每次訪問對象都要加鎖。
提升性能的 懶漢式 Singleton
publci class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
instance = LazySingleton.buildInstance();
}
return instance;
}
private static synchronized LazySingleton buildInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
只有當對象爲null
的時候,纔去加鎖創建對象。
2. 請用組合設計模式編寫程序
打印輸出圖 1 的窗口,窗口組件的樹結構如圖 2 所示,打印輸出示例參考圖 3。

組合模式的類圖:
package structure;
import java.util.ArrayList;
import java.util.List;
interface Item {
void print();
String getName();
void setName(String name);
List<Item> getChilds();
int addChild(Item item);
}
abstract class Component implements Item {
private List<Item> childs = new ArrayList<>();
private String name;
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public List<Item> getChilds() {
return childs;
}
@Override
public void print() {
String className = this.getClass().getSimpleName();
System.out.println("print " + className + "(" + getName() + ")");
List<Item> childs = getChilds();
for (Item item: childs) {
item.print();
}
}
@Override
public int addChild(Item item) {
List<Item> childs = getChilds();
if (childs == null) {
return 0;
}
if (item != null) {
childs.add(item);
}
return childs.size();
}
}
class WinForm extends Component { }
class Button extends Component { }
class CheckBox extends Component { }
class Frame extends Component { }
class Label extends Component { }
class LinkLabel extends Component { }
class PasswordBox extends Component { }
class Picture extends Component { }
class TextBox extends Component { }
public class Composition {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Item mainForm = createChild("WINDOW窗口", WinForm.class);
addChilds(mainForm);
mainForm.print();
}
static <T> Item createChild(String name, Class<T> clazz) throws IllegalAccessException, InstantiationException {
Item child = (Item)clazz.newInstance();
child.setName(name);
return child;
}
static void addChilds(Item mainForm) throws InstantiationException, IllegalAccessException {
mainForm.addChild(createChild("LOGO圖片", Picture.class));
mainForm.addChild(createChild("登錄", Button.class));
mainForm.addChild(createChild("註冊", Button.class));
Item frame = createChild("FRAME1", Frame.class);
mainForm.addChild(frame);
frame.addChild(createChild("用戶名", Label.class));
frame.addChild(createChild("文本框", TextBox.class));
frame.addChild(createChild("密碼", Label.class));
frame.addChild(createChild("密碼框", PasswordBox.class));
frame.addChild(createChild("複選框", CheckBox.class));
frame.addChild(createChild("記住用戶名", TextBox.class));
frame.addChild(createChild("忘記密碼", LinkLabel.class));
}
}
輸出結果
print WinForm(WINDOW窗口)
print Picture(LOGO圖片)
print Button(登錄)
print Button(註冊)
print Frame(FRAME1)
print Label(用戶名)
print TextBox(文本框)
print Label(密碼)
print PasswordBox(密碼框)
print CheckBox(複選框)
print TextBox(記住用戶名)
print LinkLabel(忘記密碼)