赞
踩
【作业2.3-1】在例2.6关于一个单位的互联网连接问题的软件设计中,单列模式部分采用的是标准单列模式,现在要求改变其设计,使用线程安全的单列模式。重新设计并且编写代码实现该互联网连接问题。具体要求以及代码实现参见光盘的相应作业部分。
本题目设计程序的设计类图,及其他图:
(1)President类
package com.glut.xusheng;
public class President {
private static President instance;
private String presidentName = null;
//1.单列模式的标准实现方法
private President(String name){
presidentName = name;
}
public static President getInstance(String name){
if (instance == null && !name.equals(null)){
instance = new President(name);
}
return instance;
}
public void makeSpeech(){
System.out.println("My name is" + presidentName);
System.out.println("I am the president of the United States");
}
}
(2)测试类TestSignleton
public class TestSignleton {
public static void main(String[] args) {
President president1 = President.getInstance("Bill Clinton");
president1.makeSpeech();
President president2 = President.getInstance("Bill Gates");
president2.makeSpeech();
President president3 = President.getInstance("Barack Obama");
president3.makeSpeech();
}
}
(3)类图
(4)运行截图
(1)President类
public class President {
private static President instance;
private String presidentName = null;
//2.使用线性安全单列模式设计
private President(String p){
presidentName = p;
}
public static synchronized President getInstance(String p){
if (instance == null && !p.equals(null)){
instance = new President(p);
}
return instance;
}
public void makeSpeech(){
System.out.println("My name is" + presidentName);
System.out.println("I am the president of the US in the term 3001 - 3004");
}
}
(2)运行截图
(1)President类
public class President {
private static President instance;
private String presidentName = null;
//3.单例模式---双重同步锁(懒汉模式衍生版本)
private President(String name){
presidentName = name;
}
public static President getInstance(String name){
//这里前面如果不加volatile,那么后面的双重判断将会出现"误判",导致线程不安全,所以加了保证安全
//第一重检查锁定
if (instance == null) {
synchronized (President.class) {
//第二重检查锁定
if (instance == null) {
synchronized (President.class) {
//注意:非原子操作
instance = new President(name);
}
}
}
}
return instance;
}
public void makeSpeech(){
System.out.println("My name is" + presidentName);
System.out.println("I am the president of the US 2022");
}
}
(2)运行截图
(1)President类
public class President {
//4.单例模式---静态内部类(饿汉模式衍生版本)
//优点:线程安全,并且实现了延时加载(调用效率高)
//1:初始化对象(使用的静态内部类方式)
//private static President instance;
private String presidentName = null;
private static class SingletonClassInstance {
private static final President INSTANCE = new President(null);
}
//2:构造器私有化
private President(String name){
presidentName = name;
}
//3:提供获取单实例方法
public static President getInstance(String name){
return SingletonClassInstance.INSTANCE;
}
public void makeSpeech(){
System.out.println("My name is" + presidentName);
System.out.println("I am the president of the US 2233");
}
}
(2)运行截图
(1)President类
//6.单例模式---防止反射和反序列化漏
public class President {
//1:初始化对象
//优点:这个是线程最安全,抗并发能力最强的
// * 缺点:没有延时加载
private static President instance;
private String presidentName = null;
//1:类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)
//2:私有化构造器
private President(String name){
if (instance != null){
throw new RuntimeException();
}
presidentName = name;
}
//3:提供一个单实例方法,方法同步,调用效率低
public static synchronized President getInstance(String name){
if (instance == null ){
instance = new President(name);
}
return instance;
}
public void makeSpeech(){
System.out.println("My name is " + presidentName);
System.out.println("I am the president of the United States2022");
}
}
(2)运行截图
(1)President类
//7.单例模式---枚举模式
public class President {
/**
* 推荐使用
* 优点:线程最安全
*/
private static President singleton;
//private static President instance;
private String presidentName = null;
//1.单列模式的标准实现方法
private enum Singleton{
INSTANCE;
private President singleton;
Singleton(){
singleton = new President(name());
}
public President getInstance(){
if (singleton == null ){
singleton = new President(getInstance().presidentName);
}
return singleton;
}
}
private President(String name){
presidentName = name;
}
public static President getInstance(String name){
return Singleton.INSTANCE.singleton;
}
public void makeSpeech(){
System.out.println("My name is " + presidentName);
System.out.println("I am the president of the CHINA 2202");
}
}
package com.glut.xusheng;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ClientUI extends JFrame{
private static final String CONNECT = "Create Connection";
private static final String EXIT = "Exit";
private JTextField txtInstruction;
private SingleLogonGUI objLogon = null;
public ClientUI() {
super("ClientUI - Singleton Pattern");
JButton btnConnect = new JButton(CONNECT);
JButton btnExit = new JButton(EXIT);
btnConnect.setMnemonic(KeyEvent.VK_S);
btnExit.setMnemonic(KeyEvent.VK_X);
ButtonHandler vf = new ButtonHandler();
btnConnect.addActionListener(vf);
btnExit.addActionListener(vf);
JPanel buttonPanel = new JPanel();
buttonPanel.setBackground(Color.green);
buttonPanel.add(btnConnect);
buttonPanel.add(btnExit);
txtInstruction = new JTextField("Click to get a connection");
txtInstruction.setBackground(Color.green);
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(buttonPanel, "South");
contentPane.add(txtInstruction, "Center");
setSize(320, 120);
setVisible(true);
}
private void issueWarning(){
txtInstruction.setText("Error. You cannot start a second connection.");
}
class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals(EXIT)) {
System.exit(1);
}
else if (e.getActionCommand().equals(CONNECT)) {
if(objLogon == null)
objLogon = SingleLogonGUI.getInstance();
else
issueWarning();
}
}
}
public static void main(String[] args) {
ClientUI connection = new ClientUI();
}
}// end of class
package com.glut.xusheng;
/**
* SingletonDemo1
* 测试饿汉式单例模式 优点:调用效率高 缺点:不具备延时加载
* @author
* @version 1.0
*/
public class President1 {
/**
* 1 类初始化时,立即加载这个对象(没有延时加载的优势)。加载类时,天然的是线程安全的.这里使用的private封装对象(主要是安全层面的访
* 问修饰符,和一般的属性封装为private是一样的,没有什么特别的意思)
* static修饰是为了实例化对象的时候的方便使用类名.方法名的方式得到这个类的单例对象
*/
private static President1 instance=new President1();
/**
* 2 私有构造器(在本类的如果要继续new对象可以,private,public修饰构造器没有区别,但是外部调用该类,必须使用private修饰以防止外部
* new出新对象,所以这里必须是private修饰构造器)
*/
private President1() {
}
/**
* 3 公开调用方法,方法没有同步,调用效率高!(必须要提供给外部一个方法创建这个类的单例(唯一)对象的方法,因为第一步static修饰类属性的
* (就是一个对象),所以这里也必须使用static修饰返回的对象)
*/
public static President1 getInstance(){
return instance;
}
/**
* 这是在本类测试,所以上面的化构造器即使是private修饰为私有的,但是在本类仍然可以使用构造器new对象,所以我这里写的main方法主要是为了
* 加深对构造器为什么要私有化的理解二特意在这里的,
* 当然,要测试单例,应该在另一个类中写个main方法测试(或者junit测试)
* @param args
*/
public static void main(String[] args) {
President1 instance = President1.getInstance();
System.out.println(instance);
President1 instance1 = President1.getInstance();
System.out.println(instance1);
/**
* 构造器私有化了,为什么仍然可以new的原因是因为这个main方法写在了单例类的内部,当然可以使用构造器(故意写在这里的)
*/
President1 singletonDemo1=new President1();
President1 singletonDemo2=new President1();
System.out.println(singletonDemo1);
System.out.println(singletonDemo2);
/**
* 说明:instance和instance1肯定是一个对象,但是singletonDemo1和singletonDemo2不是一个对象了
*/
}
}
package com.glut.xusheng;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/*==================================================*/
// This is a sigleton class, only one instance of the class can be created.
// To use this class, you cannot use constructor because it has been
// claimed private. You can only use the static method getInstance(),
// which, in case if the instance doesent exist, will create and return an
// instance of LogonGUI to the client class. otherwise, if an instance of
// LogonGUI has already been created before, this method will just
// return that instance to the client class.
/*==================================================*/
public class SingleLogonGUI extends JFrame {
public static final String LOGON = "Log On";
public static final String EXIT = "Exit";
private String USERNM="mikesun";
private String PASSWD = "opensesame";
private JTextField txtUser;
private JTextField txtPassWord;
private static SingleLogonGUI instance = null;
private JTextField txtInstruction;
private SingleLogonGUI() {
super("SingleLogonGUI - Singleton");
initializeGUI();
}
public static SingleLogonGUI getInstance() {
if (instance == null)
instance = new SingleLogonGUI();
return instance;
}
public void initializeGUI() {
JLabel lblUsrName = new JLabel("User Name");
JLabel lblPassWord = new JLabel("Password");
txtUser = new JTextField(USERNM);
txtPassWord = new JTextField(PASSWD);
JButton btnLogon = new JButton(LOGON);
btnLogon.setMnemonic(KeyEvent.VK_S);
JButton btnExit = new JButton(EXIT);
btnExit.setMnemonic(KeyEvent.VK_X);
ButtonHandler vf = new ButtonHandler();
btnLogon.addActionListener(vf);
btnExit.addActionListener(vf);
JPanel buttonPanel = new JPanel();
GridBagLayout gridbag = new GridBagLayout();
buttonPanel.setLayout(gridbag);
GridBagConstraints gbc = new GridBagConstraints();
buttonPanel.add(lblUsrName);
buttonPanel.add(txtUser);
buttonPanel.add(lblPassWord);
buttonPanel.add(txtPassWord);
buttonPanel.add(btnLogon);
buttonPanel.add(btnExit);
gbc.insets.top = 5;
gbc.insets.bottom = 5;
gbc.insets.left = 5;
gbc.insets.right = 5;
gbc.gridx = 0;
gbc.gridy = 0;
gridbag.setConstraints(lblUsrName, gbc);
gbc.anchor = GridBagConstraints.WEST;
gbc.gridx = 1;
gbc.gridy = 0;
gridbag.setConstraints(txtUser, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gridbag.setConstraints(lblPassWord, gbc);
gbc.anchor = GridBagConstraints.WEST;
gbc.gridx = 1;
gbc.gridy = 1;
gridbag.setConstraints(txtPassWord, gbc);
gbc.anchor = GridBagConstraints.EAST;
gbc.insets.left = 2;
gbc.insets.right = 2;
gbc.insets.top = 40;
gbc.gridx = 0;
gbc.gridy = 6;
gridbag.setConstraints(btnLogon, gbc);
gbc.anchor = GridBagConstraints.WEST;
gbc.gridx = 1;
gbc.gridy = 6;
gridbag.setConstraints(btnExit, gbc);
Container contentPane = getContentPane();
contentPane.add(buttonPanel, BorderLayout.CENTER);
txtInstruction = new JTextField();
txtInstruction.setBackground(Color.pink);
contentPane.add( txtInstruction, BorderLayout.NORTH);
setSize(320, 200);
setVisible(true);
}
public boolean isValideCustomer() {
String usr = txtUser.getText();
String pwd = txtPassWord.getText();
if(usr.equals(USERNM) && pwd.equals(PASSWD))
return true;
else
return false;
}
private void issueWarning(){
txtInstruction.setText("Invalide user name or password.");
}
private void issueSuccess(){
txtInstruction.setText("You have been successfully connected to the web.");
}
class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals(EXIT)) {
System.exit(1);
}
if (e.getActionCommand().equals(LOGON)) {
boolean isValideCus = isValideCustomer();
if(isValideCus == false){ //logon failed
issueWarning();
}
else{ //logon successfully
issueSuccess();
}
}
}
}
}// end of class
package com.glut.xusheng;
public class TestSignleton {
public static void main(String[] args) {
President president1 = President.getInstance("Bill Clinton");
president1.makeSpeech();
President president2 = President.getInstance("Bill Gates");
president2.makeSpeech();
President president3 = President.getInstance("Barack Obama");
president3.makeSpeech();
}
}
单例模式概念以及优缺点:
(1)定义:
要求一个类只能生成一个对象,所有对象对它的依赖相同。
(2)优点:
只有一个实例,减少内存开支。应用在一个经常被访问的对象上减少系统的性能开销,应用启动时,直接产生一单例对象,用永久驻留内存的方式。
避免对资源的多重占用可在系统设置全局的访问点,优化和共享资源访问。
(3)缺点:
1.一般没有接口,扩展困难。原因:接口对单例模式没有任何意义;要求“自行实例化”,并提供单一实例,接口或抽象类不可能被实例化。(当然,单例模式可以实现接口、被继承,但需要根据系统开发环境判断)
2.单例模式对测试是不利的。如果单例模式没完成,是不能进行测试的。
3.单例模式与单一职责原则有冲突。原因:一个类应该只实现一个逻辑,而不关心它是否是单例,是不是要单例取决于环境;单例模式把“要单例”和业务逻辑融合在一个类。
(4)使用场景:
1.要求生成唯一序列化的环境
2.项目需要的一个共享访问点或共享的数据点
3.创建一个对象需要消耗资源过多的情况。如:要访问IO和 数据库等资源。
4.需要定义大量的静态常量和静态方法(如工具类)的环境。可以采用单例模式或者直接声明static的方式。
(5)注意事项:
1.类中其他方法,尽量是static
2.注意JVM的垃圾回收机制。
如果一个单例对象在内存长久不使用,JVM就认为对象是一个垃圾。所以如果针对一些状态值,如果回收的话,应用就会出现故障。
3.采用单例模式来记录状态值的类的两大方法:
(一)、由容器管理单例的生命周期。Java EE容器或者框架级容器,自行管理对象的生命周期。
(二)状态随时记录。异步记录的方式或者使用观察者模式,记录状态变化,确保重新初始化也可从资源环境获得销毁前的数据。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。