常用设计模式(面试)

Singleton(单例模式)

一句话总结:一个类在Java虚拟机中只有一个对象,并提供一个全局访问点。

生活中例子:太阳、月亮、国家主席等。

解决什么问题:对象的唯一性,性能浪费太多。

项目里面怎么用:数据库连接对象,属性配置文件的读取对象。

模式结构:分为饿汉式和懒汉式(如果考虑性能问题的话,就使用懒汉式,因为懒汉式是在方法里面进行初始化的),构造器私  有化,对外提供方法加同步关键字。

框架里面使用:Struts1的Action。

JDK里面使用:java.lang.Runtime#getRuntimejava.awt.Desktop#getDesktop。

饿汉式代码:

(所谓饿汉,即jvm一加载类就会创建实例,线程安全,JVM在加载这个类时就马上创建此唯一的单例实例)

public class HurgrySingleton {  
private static HurgrySingleton hurgry=new HurgrySingleton();  
private HurgrySingleton(){};  
     public static HurgrySingleton getSinletonHurgry(){  
         return hurgry;  
        }  
}  

懒汉式代码:

(所谓懒汉,即要使用此实例时才创建,由于使用了synchronize关键字,所以也是线程安全的)

public class LarzySingleton {  
   private static LarzySingleton larzy=null;  
   private LarzySingleton(){};  
   public static synchronized Larzy getSinletonLarzy(){  
        if(larzy==null){  
              larzy=new LarzySingleton();  
        }  
        return larzy;  
    }  
}  

 这里注意饿汉式和懒汉式的实现中,均要把构造方法声明为private,以防止其他地方调用构造方法,而且,getSinleton()也要声明为static方法,以方便通过类来调用以获得实例

 双重检验实现单例模式:

(在懒汉模式中,每次调用getSinletonLazy时,不管实例是否存在,都要加锁,会导致多线程下效率低下,而我们只想在实例不存在是才加锁,实例存在时就不加锁,直接返回对象实例,那么双重校验锁则实现了这一功能)

public class Singleton {
 
    //采用volatile修饰
    private volatile static Singleton singleton;
 
    //构造方法私有化
    private Singleton(){}
 
    //双重校验锁
    public static Singleton getInstance(){
        //先判断对象是否已经实例过,没有实例化过才进入加锁代码
        if(singleton == null){
            //类对象加锁
            synchronized(Singleton.class){
                //再次判断
                if (singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

注意:singleton 采用 volatile 修饰是很有必要的,因为 singleton = new Singleton() 这句话可以分为三步:
     1. 为 singleton 分配内存空间;
     2. 初始化 singleton;
     3. 将 singleton 指向分配的内存空间。
     但是由于JVM具有指令重排的特性,执行顺序有可能变成 1-3-2。 指令重排在单线程下不会出现问题,但是在多线程下会导致一个线程获得一个未初始化的实例。例如:线程T1执行了1和3,此时T2调用 getInstance() 后发现 singleton 不为空,因此返回 singleton, 但是此时的 singleton 还没有被初始化。
     使用 volatile 会禁止JVM指令重排,从而保证在多线程下也能正常执行。

Factory(简单的工厂模式)

一句话总结:用一个方法来代替new关键字

生活中的例子:制衣厂、面包厂等生产厂。

解决什么问题:对象产生过多,或者经常有子类替换生成。

项目里面怎么用:对于经常生成的对象,或者父子类替换的对象。

模式结构:写一个对外声明的方法,方法里面使用new关键字代替。

框架里面使用:spring的核心就是工厂模式。

JDK里面使用:newInstance。

工厂模式代码:

public class UserFactory {  
     public static User createUser(int i){  
//如果输入的是1,就创建它的子类,否则就创建父类  
         if(i==1){  
             return new Alices();  
          }  
         return new User();  
     }  
}  

 

Proxy(代理模式)

一句话总结:为其他对象提供一个代理,以控制对当前对象的访问。

生活中的例子:房屋中介、婚姻介绍所。

解决什么问题:不能直接访问该对象,或者太大的资源耗费多。

项目里面怎么用:权限,或者大对象的访问权限。

模式结构:代理类和被代理类实现同一个接口,用户访问的时候先访问代理对象,然后让代理对象去访问被代理对象。

框架里面使用:Spring里面的AOP实现。

JDK里面使用:java.lang.reflect.Proxy。

 

代理模式代码:

创建一个接口:

public interface SellHouse {  
    void sell(double money);  
}  

 

创建一个被代理类:

        

public class Hoster implements SellHouse {  
        @Override  
        public void sell(double money) {  
            System.out.println("祝你居住愉快");  
        }  
    }  

 

创建一个代理类:

 

public class Medium implements SellHouse {  
    SellHouse hoster=new Hoster();  
    @Override  
    public void sell(double money) {  
        if(money>=1000){  
            hoster.sell(money);  
        }else{  
            System.out.println("你的价格太低了");  
        }  
    }  
}  

测试类:

 

public class Renter {  
    public static void main(String[] args) {  
        SellHouse renter=new Medium();  
        renter.sell(500);  
    }  
}  

 

 

Adapter(适配器模式)

一句话总结:将两个原来不兼容的类兼容起来一起工作。

生活中的例子:变压器、充电器

解决什么问题:已经存在的相同功能的代码,但是接口不兼容,不能直接调用。

项目里面怎么用:在使用旧的API的时候,没有源码,和新的不能兼容。

模式结构:分为类适配器和对象适配,一般常用的就是对象适配器,因为组合由于继承。

框架里面使用:单元测试里面的asserEquels。

JDK里面使用:java.util.Arrays#asListjava.io.InputStreamReader(InputStream) java.io.outputStreamWriter(OutputStream)。

 

 

Strategy(策略模式)

一句话总结:定义一系列算法并可以互相替换。

生活中的例子:图片的格式,压缩文件的格式。

解决什么问题:做一件事情有很多种方法。

项目里面怎么用:购物车里面的付款方式。

模式结构:声明一个顶级接口,定义一个策略方法,具体的实例都要实现这个接口。

框架里面使用:hibernate的主键生成策略。

JDK里面使用:java.util.Comparator#compare。

 

策略模式代码:

定义一个顶级接口:

public interface Person {  
    void repast();  
}  

具体的实例类1:

public class African implements Person {  
    @Override  
    public void repast() {  
        System.out.println("非洲人用手吃饭");  
    }  
}  

具体的实例类2:

public class America implements Person {  
    @Override  
    public void repast() {  
        System.out.println("美国人用刀叉吃饭");  
    }  
}  

具体的实例类3:

public class Chinese implements Person {  
    @Override  
    public void repast() {  
        System.out.println("中国人用筷子吃饭");  
    }  
}  

测试类:

public class Test {  
    public static void main(String[] args) {  
        Person chinese=new Chinese();  
        Person america=new America();  
        Person african=new African();  
        chinese.repast();  
        america.repast();  
        african.repast();  
    }  
}  

 

Template(模板模式)

一句话总结:父类定义流程,子类实现流程。

生活中的例子:iphone生产有多个国家,但流程只有一个。

解决什么问题:业务有多种,但都有规定的流程。

项目里面怎么用:一般基类的实现都是模板模式,BaseDAO,bBaseService。

模式结构:定义一个抽象父类定义流程,或者常用方法和常量,子类继承父类,实现具体的细节方法。

框架里面使用:hibernate里面的方言,是跨数据库的基础。

JDK里面使用:IO流里面的InputStream,Writer等。

 

模板模式代码:

//定义一个父类,定义流程

public abstract class IPhoneTemplate {  
    public void createIPhone(){  
        setupCpu();  
        setupAll();  
        check();  
        box();  
    }  
    protected abstract void box();  
    protected abstract boolean check();   
    protected abstract void setupAll();  
    protected abstract void setupCpu();   
}  

//子类实现父类的细节方法1

public class ChinaIPhone extends IPhoneTemplate {  
    @Override  
    protected void box() {  
        System.out.println("box()");  
    }  
    @Override  
    protected boolean check() {  
        System.out.println("check()");  
        return true;  
    }  
    @Override  
    protected void setupAll() {  
        System.out.println("setupAll()");  
    }  
    @Override  
    protected void setupCpu() {  
        System.out.println("setupCpu()");  
    }  
}  


//子类实现父类的细节方法2

public class AfricanIPhone extends IPhoneTemplate {  
    @Override  
    protected void box() {  
        System.out.println("box()");  
    }  
    @Override  
    protected boolean check() {  
        System.out.println("check()");  
        return true;  
    }  
    @Override  
    protected void setupAll() {  
        System.out.println("setupAll()");  
    }  
    @Override  
    protected void setupCpu() {  
        System.out.println("setupCpu()");  
    }  
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值