您的位置:首页 > 其它

14.设计模式、单例模式、适配器模式

2018-03-09 18:29 375 查看
设计模式
设计模式|菜鸟教程

1.什么是设计模式(Design Patterns)?你用过哪种设计模式?用在什么场合
2.你知道哪些商业级设计模式?
3.哪些设计模式可以增加系统的可扩展性
4.除了单例模式,你在生产环境中还用过什么设计模式?
5.写 Singleton 单例模式
6.单例模式的双检锁是什么
7.如何创建线程安全的 Singleton
8.适配器模式是什么?什么时候使用
9.适配器模式和代理模式之前有什么不同
10.适配器模式和装饰器模式有什么区别
11.什么时候使用享元模式
12.什么时候使用组合模式
13.什么时候使用访问者模式
14.什么是模板方法模式
15.请给出1个符合开闭原则的设计模式的例子

1.什么是设计模式(Design Patterns)?你用过哪种设计模式?用在什么场合一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;
使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;
设计模式使代码编制  真正工程化;
设计模式使软件工程的 基石脉络, 如同大厦的结构一样;
并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;
能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引起麻烦的紧耦合,以增强软件设计面对并适应变化的能力。
2.你知道哪些商业级设计模式?不造咋答。一般用的多的单例、策略、适配器、命令、建造者工厂
3.哪些设计模式可以增加系统的可扩展性工厂模式
抽象工厂模式
观察者模式:很方便增加观察者,方便系统扩展
模板方法模式:很方便的实现不稳定的扩展点,完成功能的重用
适配器模式:可以很方便地对适配其他接口
代理模式:可以很方便在原来功能的基础上增加功能或者逻辑
责任链模式:可以很方便得增加拦截器/过滤器实现对数据的处理,比如struts2的责任链
策略模式:通过新增策略从而改变原来的执行策略
扩展:
1.Load Balancer 负载均衡 分发器根据一定的规则将请求发送到某个工作示例处理
2.Scatter and Gather 分散聚集模式 分发器将请求分发到线程池中多个线程,每个线程计算本地线程结果后发回分发器,分发器合并结果后返回。
3.Result Cache 结果缓存 分发器会先查下请求是否已经缓存,如果被缓存过并且没过期则直接返回缓存中的结果,
4.Shared Space 共享空间 所有工作者线程通过共享空间共享数据,共享数据是为了协调各个线程的并发和数据分隔任务分隔问题。
5.Pipe and Filter 管道过滤器模式 所有的工作者用管道连接起来,数据流通过管理中的过滤器顺序执行
6.MapReduce 使用分布式文件系统来解决单个磁盘的IO问题
7.Bulk Synchronous Parallel 批量同步并行模式 基于master机器的锁机制来协调各个工作者线程并行执行
8.Execution Orchestrator 执行协调器 任务管理和分发的协调器,用于将任务争取分发都各个工作者线程执行
4.除了单例模式,你在生产环境中还用过什么设计模式?策略、适配器、命令、建造者工厂
5.写 Singleton 单例模式1. 懒汉模式
public class SingletonDemo {
private static SingletonDemo instance;
private SingletonDemo(){

}
public static SingletonDemo getInstance(){
if(instance==null){
instance=new SingletonDemo();
}
return instance;
}
}
2. 线程安全的懒汉模式
public class SingletonDemo {
private static SingletonDemo instance;
private SingletonDemo(){

}
public static synchronized SingletonDemo getInstance(){
if(instance==null){
instance=new SingletonDemo();
}
return instance;
}
}
3. 饿汉模式
public class SingletonDemo {
private static SingletonDemo instance=new SingletonDemo();
private SingletonDemo(){

}
public static SingletonDemo getInstance(){
return instance;
}
}
4. 静态类内部加载
public class SingletonDemo {
private static class SingletonHolder{
private static SingletonDemo instance=new SingletonDemo();
}
private SingletonDemo(){
System.out.println("Singleton has loaded");
}
public static SingletonDemo getInstance(){
return SingletonHolder.instance;
}
}
5. 枚举方法
enum SingletonDemo{
INSTANCE;
public void otherMethods(){
System.out.println("Something");
}
}
6. 双重校验锁法
public class SingletonDemo {
private volatile static SingletonDemo instance;
private SingletonDemo(){
System.out.println("Singleton has loaded");
}
public static SingletonDemo getInstance(){
if(instance==null){
synchronized (SingletonDemo.class){
if(instance==null){
instance=new SingletonDemo();
}
}
}
return instance;
}
}

6.单例模式的双检锁是什么
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) {  //1
if (instance == null)          //2
instance = new Singleton();  //3
}
}
return instance;
}
双重检查锁定背后的理论是:在 //2 处的第二次检查使(如清单 3 中那样)创建两个不同的 
Singleton
 对象成为不可能。假设有下列事件序列:线程 1 进入 
getInstance()
 方法。 

由于 
instance
 为 
null
,线程 1 在 //1 处进入 
synchronized
 块。 

线程 1 被线程 2 预占。

线程 2 进入 
getInstance()
 方法。

由于 
instance
 仍旧为 
null
,线程 2 试图获取 //1 处的锁。然而,由于线程 1 持有该锁,线程 2 在 //1 处阻塞。

线程 2 被线程 1 预占。

线程 1 执行,由于在 //2 处实例仍旧为 
null
,线程 1 还创建一个 
Singleton
 对象并将其引用赋值给 
instance


线程 1 退出 
synchronized
 块并从 
getInstance()
 方法返回实例。 

线程 1 被线程 2 预占。

线程 2 获取 //1 处的锁并检查 
instance
 是否为 
null
。 

由于 
instance
 是非 
null
 的,并没有创建第二个 
Singleton
 对象,由线程 1 创建的对象被返回。
双重检查锁定背后的理论是完美的。不幸地是,现实完全不同。双重检查锁定的问题是:并不能保证它会在单处理器或多处理器计算机上顺利运行。双重检查锁定失败的问题并不归咎于 JVM 中的实现 bug,而是归咎于 Java 平台内存模型。内存模型允许所谓的“无序写入”,这也是这些习语失败的一个主要原因。7.如何创建线程安全的 Singleton静态内部类的方式创建单例模式(static inner class)[java] view plain copypublic class Singleton {  
    private Singleton() {  
    }  
    private static class SingletonHolder {// 静态内部类  
        private static Singleton singleton = new Singleton();  
    }  
    public static Singleton getInstance() {  
        return SingletonHolder.singleton;  
    }  


8.适配器模式是什么?什么时候使用适配器(变压器)模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口原因不匹配而无法一起工作的两个类能够一起工作。适配类可以根据参数返还一个合适的实例给客户端。
VO、DO、DTO、BO之间适配
配器模式主要是在程序代码写好之后 又遇到了需要使用新对象的情况 新的对象和原来使用的对象 本质上是一种 但是里面的方法和属性都不相同 所以为了减少代码的修改 就像电源适配器一样 使用不同的对象的一种方法
9.适配器模式和代理模式之前有什么不同        参考链接适配器模式是因为新旧接口不一致导致出现了客户端无法得到满足的问题,但是,由于旧的接口是不能被完全重构掉的,因为我们还想使用实现了这个接口的一些服务。那么为了使用以前实现旧接口的服务,我们就应该把新的接口转换成旧接口;实现这个转换的类就是抽象意义的转换器。
就比如在java中早期的枚举接口是Enumeration而后定义的枚举接口是Iterator;有很多旧的类实现了enumeration接口暴露出了一些服务,但是这些服务我们现在想通过传入Iterator接口而不是Enumeration接口来调用,这时就需要一个适配器,那么client就能用这个服务了(服务端只想用Iterator或者只知道这个接口)。
相比于适配器的应用场景,代理就不一样了,虽然代理也同样是增加了一层,但是,代理提供的接口和原本的接口是一样的,代理模式的作用是不把实现直接暴露给client,而是通过代理这个层,代理能够做一些处理。
10.适配器模式和装饰器模式有什么区别        参考链接适配器模式主要是为了接口的转换,而装饰者模式关注的是通过组合来动态的为被装饰者注入新的功能或行为(即所谓的责任)。
适配器将一个对象包装起来以改变其接口;装饰者将一个对象包装起来以增强新的行为和责任;而外观将一群对象包装起来以简化其接口
11.什么时候使用享元模式系统有大量相似对象。 需要缓冲池的场景。
如:JAVA中的 String,如果有则返回,如果没有则创建一个字符串保存在字符串缓存池里面。数据库的数据池。
12.什么时候使用组合模式部分、整体场景,如树形菜单,文件、文件夹的管理。
如:算术表达式包括操作数、操作符和另一个操作数,其中,另一个操作符也可以是操作树、操作符和另一个操作数。在JAVA AWT和SWING中对于Button和Checkbox是树叶Container是树枝。
13.什么时候使用访问者模式对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。
注意事项:访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。
如:您在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。
14.什么是模板方法模式意图:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
主要解决:一些方法通用,却在每一个子类都重新写了这一方法。
何时使用:有一些通用的方法。
如何解决:将这些通用算法抽象出来。
关键代码:在抽象类实现,其他步骤在子类实现。
应用实例: 1、在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异。 2、西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架。 3、spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。
优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。
注意事项:为防止恶意操作,一般模板方法都加上 final 关键词。
15.请给出1个符合开闭原则的设计模式的例子        参考链接对扩展开放、对修改关闭
策略模式、简单工厂、工厂方法、抽象工厂、建造者模式、桥梁模式、外观模式、中介模式、迭代子模式
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: