组合模式及单例模式

用户头像
garlic
关注
发布于: 2020 年 10 月 04 日
组合模式及单例模式



组合模式





将一组对象组织(Compose)成树形结构,以表示一种“部分 - 整体”的层次结构。



示例:文本打印



组合设计模式模拟窗口显示



Component.java



public interface Component{
public String getName();
public void print();
}




Composite.java



import java.util.ArrayList;
import java.util.List;

public class Composite implements Component{
private String name;
private List<Component> componentList = new ArrayList<Component>();


public Composite(String name){
this.name = name;
}

public String getName(){
return this.name;
}

public void add(Component component){
componentList.add(component);
}

public void print() {
System.out.println(name);
for (Component component : componentList) {
component.print();
}
}

}


Leaf.java

public class Leaf implements Component {

private String name;

public Leaf(String name) {

this.name = name;
}


public String getName() {

return this.name;
}

public void print() {
System.out.println(name);
}

}



Windows.java

public class Windows {


public static void print(){
Composite winform = new Composite("WinForm(WINDOW窗口)");
Leaf picture = new Leaf("Picture(LOGO图片)");
Leaf loginbutton = new Leaf("Button(登录)");
Leaf registerbutton = new Leaf("Button(注册)");

winform.add(picture);
winform.add(loginbutton);
winform.add(registerbutton);

Composite frame = new Composite("Frame(FRAME1)");
Leaf label = new Leaf("Lable(用户名)");
Leaf textbox = new Leaf("Text(文本框)");
Leaf password = new Leaf("PasswordBox(密码框)");
Leaf checkbox = new Leaf("CheckBox(复选框)");
Leaf textbox2 = new Leaf("TextBox(记住用户名)");
Leaf linklabel = new Leaf("Linkable(忘记密码)");

frame.add(label);
frame.add(textbox);
frame.add(password);
frame.add(checkbox);
frame.add(textbox2);
frame.add(linklabel);

winform.add(frame);
winform.print();

}
public static void main(String[] args) {
print();
}

}




示例:java swing图形打印





Button.java

import javax.swing.*;
public class Button extends JButton {

public void print() {
System.out.println(getText());
}
public Button(String text) {
super(text, null);
print();
}
}



CheckBox.java

import javax.swing.*;

public class CheckBox extends JCheckBox {
public void print() {
System.out.println(getText());
}

public CheckBox (String text) {
super(text, null, false);
print();
}

}




Frame.java

import javax.swing.*;

public class Frame extends JPanel {
private String name;
public void print() {
System.out.println(name);
}
public Frame(String text) {
super(true);
this.name = text;
print();
}
}




Label.java

import javax.swing.*;

public class Lable extends JLabel {
//private String name;
public void print() {
System.out.println(getText());
}
public Lable(String text) {
super(text, null, LEADING);
//this.name = text;
print();
}


}



Linkable.java

import javax.swing.*;
import java.awt.*;

public class Linkable extends JLabel {

public void print() {
System.out.println(getText());
}
public Linkable(String text) {
super(text, null, LEADING);
this.setForeground(Color.BLUE.darker());
this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
print();
}

}




Picture.java

import javax.swing.*;
import java.awt.*;

public class Picture extends JLabel{
//private String name;
public void print() {
System.out.println(getText());
}

public Picture(String text, String ImageName) {
super(text, null, LEADING);
Image image = new ImageIcon(ImageName).getImage();
setIcon(new ImageIcon(image));
//his.name = text;
print();
}
}




TextBox.java



import javax.swing.*;

public class TextBox extends JTextField {
//JTextComponent 有同名函数
public void printbox() {
System.out.println(getText());
}
public TextBox(String text) {
super(null, text, 0);
printbox();
}


}




WinForm.java

import javax.swing.*;
import java.awt.*;

public class WinForm extends JFrame {
//private String name;

public WinForm(String title) throws HeadlessException {
super(title);
super.frameInit();
//this.name = title;
print();
}
public void print() {
System.out.println(getTitle());
}
}




Windows.java


import org.w3c.dom.Text;

import javax.swing.*;
import java.awt.*;

public class Windows {
public static void main(String args[]) {

WinForm winForm = new WinForm("Window窗口");

winForm.setSize(600, 400);
winForm.setLocationRelativeTo(null);
winForm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Picture picture = new Picture("LOGO图片","d:/background.jpg");
picture.setBounds(200, 10, 160, 120);
winForm.add(picture);

Button loginButton = new Button("登录");
loginButton.setBounds(200, 300, 80, 25);
winForm.add(loginButton);

Button registerButton = new Button("注册");
registerButton.setBounds(300, 300, 80, 25);
winForm.add(registerButton);

Frame frame = new Frame("FRAME1");
frame.setLayout(null); //设置布局为 null
winForm.add(frame);

Lable userName = new Lable("用户名");
userName.setBounds(100, 160, 80, 25);
frame.add(userName);

TextBox userNameBox = new TextBox("用户名文本框");
userNameBox.setBounds(150, 160, 80, 25);
frame.add(userNameBox);

Lable passWord = new Lable("密码");
passWord.setBounds(100, 210, 80, 25);
frame.add(passWord);

TextBox passWordBox = new TextBox("用户名文本框");
passWordBox.setBounds(150, 210, 80, 25);
frame.add(passWordBox);

CheckBox rememberPwd = new CheckBox("记住户名");
rememberPwd.setBounds(100, 250, 80, 25);
//rememberPwd.setSize(,200);
frame.add(rememberPwd);
/*
Lable rememberPwdLabel = new Lable("记住用户名");
rememberPwdLabel.setBounds(180, 250, 80, 25);
frame.add(rememberPwdLabel);
*/
Linkable retrievePwd = new Linkable("忘记密码");
retrievePwd.setBounds(350, 250, 80, 25);
frame.add(retrievePwd);

winForm.setVisible(true);
}

}




输出结果:





单例模式



实现类只创建一个实例。



私有构造函数: 使得外部无法通过new创建实例,

静态方法:能通过类获取类实例

私有静态变量:使得类实例化创建惟一对象。



  • 饿汉模式(推荐)

定义类时,单实例创建。

特点: 启动慢,引用快。



  • 懒汉模式

获取实例的时创建,需要synchronized同步等待,防止并发处理异常。

特点: 启动快,引用慢。





2020/10/11 更新



根据助教老师的建议又看了下 double-checked locking 方式实现的单例


public class Singleton {
private Singleton() {}
private volatile static Singleton instance = null;

public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}

}



对于 volatile, 查到网上帖子, 大多是是说由于编译器优化导致的指令重排可能导致new出来的对象的部分初始化问题, 我 查到的 比较早的资料 "Double-Checked Locking is Broken" Declaration

https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html 提到 the Symantec JIT 会在构造函数前对申请对象的引用赋值。



最后一个解决方案来自Joshua Block的Effective Java(第3册),使用枚举.



public enum Singleton {
INSTANCE;
...
}



2020-10-28 更新参考老师讲义写了个一个单例的工厂方法。



SingletonFactory.java

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class SingletonFactory {
private final static Properties IMPLS = loadImpls();


private static Properties loadImpls() {
Properties defaultImpls = new Properties();
Properties impls = new Properties(defaultImpls);

defaultImpls.setProperty("Singleton","Singleton");

try{
impls.load(SingletonFactory.class.getResourceAsStream("singleton.properties"));
} catch (IOException e){
throw new RuntimeException(e);
}
return impls;
}
@SuppressWarnings("unchecked")
public static <T> T getSingleton() {
String implClassName = IMPLS.getProperty("Singleton");
try {
Class implClass = Class.forName(implClassName);
Method m = implClass.getMethod("getInstance");
return (T) m.invoke(null);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}




Singleton.java

public abstract class Singleton {
public static Singleton getInstance(){
return null;
};
}




SingleNormal.java

public class SingletonNormal extends Singleton{
private SingletonNormal(){System.out.println("Normal Singleton");};
private static SingletonNormal instance = new SingletonNormal();
public static Singleton getInstance(){
return instance;
}
}




SingleDoubleCheck.java

public class SingletonDoubleCheck extends Singleton{
private SingletonDoubleCheck(){System.out.println("Double check Thread Safe Singleton");}
private volatile static SingletonDoubleCheck instance = null;
public static Singleton getInstance() {
if (instance == null){
synchronized (SingletonDoubleCheck.class){
if (instance == null){
instance = new SingletonDoubleCheck();
}
}
}
return instance;
}
}




SingletonLazy.java

public class SingletonLazy extends Singleton {
private SingletonLazy() {System.out.println("Thread Safe Singleton");};
private volatile static SingletonLazy instance = null;

public static synchronized Singleton getInstance(){
if (instance == null){
instance = new SingletonLazy();
}
return instance;
}
}




Client.java

public class Client {
public static void main(String[] args){
Singleton singleton1 = (Singleton) SingletonFactory.getSingleton();
Singleton singleton2 = (Singleton) SingletonFactory.getSingleton();
System.out.println(singleton1==singleton2);

}
}


singleton.properties

Singleton=SingletonNormal



验证输出:

Normal Singleton
true



可以通过修改配置文件 singleton.properties里 Singleton 指定不同的实现方式。



参考及引用



架构师训练营作业-李智慧老师相关讲义

Photo by Adrianna Calvo from Pexels



用户头像

garlic

关注

还未添加个人签名 2017.11.15 加入

还未添加个人简介

评论

发布
暂无评论
组合模式及单例模式