java—单例模式
1)需求
比如,任务管理器打开后,再次打开不会打开新窗口,还是刚才的窗口
要点:
某个类只有一个实例
它必须自行创建这个实例;
必须向整个系统提供这个实例;
2)实现
首先是未实现单例模式的效果
package window;
public class TaskMangerWindow {
public TaskMangerWindow() {
System.out.println("任务管理器创建");
}
public void show() {
System.out.println("任务管理器显示");
}
}
package singleton1;
import window.TaskMangerWindow;
public class Main {
public static void click() {
TaskMangerWindow tmw=new TaskMangerWindow();
tmw.show();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
click();
click();
}
}
实验结果:任务管理器创建
任务管理器显示
任务管理器创建
任务管理器显示
显然创建了俩个页面。
最原始的单例模式
用静态变量实现,俩次点击只创建一个对象。
package singleton2;
import window.TaskMangerWindow;
class SystemConf{
public static TaskMangerWindow tmw=new TaskMangerWindow();
}
public class Main {
public static void click() {
TaskMangerWindow tmw=SystemConf.tmw;//点击时创建了一个静态的对象
tmw.show();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
click();
click();
}
}
结果:
任务管理器创建
任务管理器显示
任务管理器显示
首次改进
由于最原始的多了一个SystemConf类,可以把实现静态对象直接放在原来的类中,即在类中即实现了一个自己静态的对象。
package window;
public class TaskMangerWindow {
public static TaskMangerWindow tmw=new TaskMangerWindow();
public TaskMangerWindow() {
System.out.println("任务管理器创建");
}
public void show() {
System.out.println("任务管理器显示");
}
}
package singleton2;
import window.TaskMangerWindow;
class SystemConf{
}
public class Main {
public static void click() {
TaskMangerWindow tmw=TaskMangerWindow.tmw;
tmw.show();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
click();
click();
}
}
结果:
任务管理器创建
任务管理器显示
任务管理器显示
再次改进
首次改进后代码仍然有以下缺陷:
(1)虽然用户可以用TaskMangerWindow.tmw使用任务管理器窗口对象,但是也可以通过new来实例化。
(2)在一般情况下将成员变量定义为私有的,但此处的TaskMangerWindow中的成员tmw是public的。
改进方法:在第一个问题中只需将构造函数定义为私有的;第二个问题只需将tmw成员定义为私有,然后用一个函数获取。
package window;
public class TaskMangerWindow {
private static TaskMangerWindow tmw=new TaskMangerWindow();
public static TaskMangerWindow get() {
return tmw;
}
private TaskMangerWindow() {
System.out.println("任务管理器创建");
}
public void show() {
System.out.println("任务管理器显示");
}
}
package singleton2;
import window.TaskMangerWindow;
public class Main {
public static void click() {
TaskMangerWindow tmw=TaskMangerWindow.get();
tmw.show();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
click();
click();
}
}
2利用继承和多态扩充程序功能
1)需求简介
假如编写了一个图像处理文件,能够显示一副图片。
package imageprocess;
public class ImageProcessor {
public void show() {
System.out.println("显示一幅图片");
}
}
package imageprocess;
public class Main1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
ImageProcessor ip=new ImageProcessor();
ip.show();
}
}
要在ImageProcessor类中在显示图片之前加一个去噪声的操作,不改变ImageProcessor类的情况下实现。
实现方法:继承ImageProcessor类,show()函数重写一下,加入新操作
package imageprocess;
public class ImageProcessor {
public void show() {
System.out.println("显示一幅图片");
}
}
package imageprocess;
import newimageprocessor.NewImageProcessor;
import noiseope.NoiseOpe;
public class Main1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
NewImageProcessor ip=new NewImageProcessor(new NoiseOpe());
ip.show();
}
}
package newimageprocessor;
import imageprocess.ImageProcessor;
import noiseope.NoiseOpe;
public class NewImageProcessor extends ImageProcessor {
private NoiseOpe no;
public NewImageProcessor(NoiseOpe a) {
this.no=a;
}
public void show() {
no.work();
super.show();
}
}
package noiseope;
public class NoiseOpe {
public void work() {
System.out.println("去噪声");
}
}
结果:
去噪声
显示一幅图片
出现的问题
NewImageProcessor类中的参数只能是NoiseOpe类型,即只能由这个模块提供服务。写了新模块或NoiseOpe改进为NewNoiseOpe就无法传入
改进
利用多态性解决这个问题,定义一个接口INoiseOpe,要求无论NoiseOpe还是NewNoiseOpe都实现这个接口就可以了。