设计模式笔试面试常见问题

设计模式有哪几种
单例模式中如何实现并发的懒汉模式
1. 最简单的实现
首先,能够想到的最简单的实现是,把类的构造函数写成private的,从而保证别的类不能实例化此类,然后在类中提供一个静态的实例并能够返回给使用者。这样,使用者就可以通过这个引用使用到这个类的实例了。
public class SingletonClass {
private static final SingletonClass instance = new SingletonClass ();
public static SingletonClass getInstance() {
return instance;
}
private SingletonClass() {
}
}
如上例,外部使用者如果需要使用SingletonClass的实例,只能通过getInstance()方法,并且它的构造方法是private的,这样就保证了只能有一个对象存在。
2. 性能优化——lazy loaded
上面的代码虽然简单,但是有一个问题——无论这个类是否被使用,都会创建一个instance对象。如果这个创建过程很耗时,比如需要连接10000次数据库(夸张了…:-)),并且这个类还并不一定会被使用,那么这个创建过程就是无用的。怎么办呢?
为了解决这个问题,我们想到了新的解决方案:
public class SingletonClass {
private static SingletonClass instance = null;
public static SingletonClass getInstance() {
if(instance == null) {
instance = new SingletonClass();
}
return instance;
}
private SingletonClass() {
}
}
代码的变化有两处——首先,把instance初始化为null,直到第一次使用的时候通过判断是否为null来创建对象。因为创建过程不在声明处,所以那个final 的修饰必须去掉。
我们来想象一下这个过程。要使用SingletonClass,调用getInstance()方法。第一次的时候发现instance是null,然后就新建一个对象,返回出去;第二次再使用的时候,因为这个instance是static的,
所以已经不是null了,因此不会再创建对象,直接将其返回。
这个过程就成为lazy loaded,也就是迟加载——直到使用的时候才进行加载。
3. 同步
上面的代码很清楚,也很简单。然而就像那句名言:“80%的错误都是由20%代码优化引起的”。单线程下,这段代码没有什么问题,可是如果是多线程,麻烦就来了。我们来分析一下:
线程A希望使用SingletonClass,调用getInstance()方法。因为是第一次调用,A就发现instance是null的,于是它开始创建实例,就在这个时候,CPU发生
时间片切换,线程B开始执行,它要使用SingletonClass,调用getInstance()方法,同样检测到instance是null——注意,这是在A检测完之后切换的,也就是说A并没有来得及创建对象——因此B开始创建。B创建完成后,切换到A 继续执行,因为它已经检测完了,所以A不会再检测一遍,它会直接创建对象。这样,线程A和B各自拥有一个SingletonClass的对象——单例失败!
解决的方法也很简单,那就是加锁:
public class SingletonClass {
private static SingletonClass instance = null;
public synchronized static SingletonClass getInstance() {
if(instance == null) {
instance = new SingletonClass();
}
return instance;
}
private SingletonClass() {
}
}
是要getInstance()加上同步锁,一个线程必须等待另外一个线程创建完成后才能使用这个方法,这就保证了单例的唯一性。
4. 又是性能
上面的代码又是很清楚很简单的,然而,简单的东西往往不够理想。这段代码毫无疑问存在性能的问题——synchronized修饰的同步块可是要比一般的代码段慢上几倍的!如果存在很多次getInstance()的调用,那性能问题就不得不考虑了!简易过滤器
让我们来分析一下,究竟是整个方法都必须加锁,还是仅仅其中某一句加锁就足
够了?我们为什么要加锁呢?分析一下出现lazy loaded的那种情形的原因。原因就是检测null的操作和创建对象的操作分离了。如果这两个操作能够原子地进行,那么单例就已经保证了。于是,我们开始修改代码:
public class SingletonClass {
private static SingletonClass instance = null;
public static SingletonClass getInstance() {
synchronized(SingletonClass.class) {
if(instance == null) {
instance = new SingletonClass();
}
}
return instance;
}
private SingletonClass() {
}
}
首先去掉getInstance()的同步操作,然后把同步锁加载if语句上。但是这样的修改起不到任何作用:因为每次调用getInstance()的时候必然要同步,性能问题还是存在。如果……如果我们事先判断一下是不是为null再去同步呢?
public class SingletonClass {
private static SingletonClass instance = null;
public static SingletonClass getInstance() {
if(instance == null) {
synchronized(SingletonClass.class) {
if(instance == null) {
instance = new SingletonClass();
}
}
}
return instance;
}
private SingletonClass() {
}
}
还有问题吗?首先判断instance是不是为null,如果为null,加锁初始化;如果不为null,直接返回instance。
这就是double-checked locking设计实现单例模式。到此为止,一切都很完美。我们用一种很聪明的方式实现了单例模式
责任链
问题A:实行一个过滤功能,过滤一段文字
首先获取用户输入的一段文字:String msg = "大家好:),<script>,敏感,被就业,网络授课没感觉,因为看不见大家伙儿";
那么我们写一个  filterMethod(){};  使用最简单的replace方法替换文中的敏感词
问题B:如果想用面向对象的方法去实现呢?
创建一个类MsgProcessor专门用来处理用户输入的文字,该类用一个属性message(用户输入文字),生成set/get方法,
(为什么要通过set/get方法去访问属性,而不直接访问该属性???为了保护该属性,不让用户直接访问修改,如果是你的存折,你可以在set/get方法中加入权限判断,避免让用户直接访问操作;如果让该属性只能够看,不能够修改,则直接删除set方法即可)
一个方法process()(处理文字)    每次只需要将
MsgProcessor mp = new MsgProcessor();
mp.setMsg(msg);    mp.process();
问题C:如果我们有多个过滤器,那么如何设计会更加方便以后继续添加??首先我们写一个接口Filter,它有一个doFilter方法,
public interface Filter {
String doFilter(String str);  }
制作接口相当于给所有开发人员制定了规范,然后我们写的每一个过滤器类都要实现该接口,由于有多个过滤器类,所以我们建立一个过滤器类的集合类FilterChain,它需要实现Filter接口,同时要拥有过滤器集合变量public class FilterChain implements Filter {
用集合的好处当有新的过滤器或者过滤器集合类要添加进来,会更加方便List<Filter> filters = new ArrayList<Filter>();
public FilterChain addFilter(Filter f) {
//能够将子类生成的对象赋值给父类,但是不能将父类生成的对象赋值给子类//并且能够将实现接口的类的对象赋值给父类接口,同上一样
this.filters.add(f);
return this;//返回this,也就是返回FilterChain 本身对象}
public String doFilter(String str) {
String r = str;
for(Filter f: filters) {
r = f.doFilter(r);
}  //逐个调用过滤器的dofilter方法
return r;
}
那么单个的过滤器例如HTMLFilter,只需要执行自己的操作
public class HTMLFilter implements Filter {
@Override
public String doFilter(String str) {
//process the html tag <>
String r = place('<', '[')
.replace('>', ']');
return r;
} }
通常我们不希望这样添加
Filter[] filters = {new HTMLFilter(), new SesitiveFilter(), new FaceFilter()};
因为这样会使得每次只要添加新的过滤器,都要修改这个类,所以我们直接使用集合。
那么在main函数中,由于addFilter返回的this,所以可以连写
FilterChain fc = new FilterChain();
fc.addFilter(new HTMLFilter())
.addFilter(new SesitiveFilter())
.addFilter(new FaceFilter()) ;
问题D:如何继续优化该段代码呢?我们希望msgProcess的process方法执行何功能?
也就是需要在MsgProcessor类中加入成员变量FilterChain fc;  public String process() {
return fc.doFilter(msg);
}
那么要想用MsgProcessor类的对象调用process方法,就必须要在MsgProcessor类中生成fc的set/get方法;
String result = mp.process();

本文发布于:2024-09-22 01:14:22,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/3/351138.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:方法   使用   创建   对象
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议