栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

设计模式相关面试题集合

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计模式相关面试题集合

1、单例模式

定义:它是java所有设计模式中最简单的一种,它提供了一个创建对象的最佳方法,

那些地方用到了单例模式?

1、网站计数器,一般采用单例模式,否则难以同步
2、应用程序的日志应用一般采用单例模式
3、多线程的线程池一般也是采用单例模式
4、windows中的任务管理器是典型的单例模式,不可以开启两个
5、windows中的回收站也是单例模式

单例模式的创建?

主要是懒汉式和饿汉式

1、饿汉式:

类初始化的时候会立刻加载该对象,天生的线程安全,调用效率高。

饿汉式实现的步骤:
1、构造器私有化.
2、类的内部创建一个对象的实例。
3、向外提供一个静态的方法用来获取对象的实例。

优点:在类加载的过程中就创建的实例,避免的线程同步的问题(线程的聚绝对安全)。
缺点:如果从开始的时候就没有使用这个实例,就造成的内存的浪费。

class Singleton{
    //1.私有化构造器
    private Singleton(){
    }
    //类的内部创建一个对象实例
    private  final  static Singleton instance =new Singleton();
    //3.提供一个公有的静态的方法,返回对象的实例
     public static Singleton getInstance(){
         return  instance;
     }
}

 public static void main(String[] args) {
        //测试
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        //调用两个方法获取的对象实例,是相同的
        System.out.println(instance==instance1);
        //获取两个实例的hashcode
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());
    }

true
1956725890
1956725890
2、懒汉式:

类初始化的时候,不会初始化该对象,真正使用的时候才会创建该对象,具有懒加载的功能。

实现步骤:
1、私有化构造器
2、向外提供一个静态的方法,用来获取对象的实例。

优点:实现了懒加载的效果,但是只能在单线程的情况下使用。
缺点:如果两个线程同时进入了if条件语句,那么就会创建多个实例(线线程不安全)

class  Singleton{
    //1.私有化构造器
    private Singleton(){
    }
    private static Singleton instance;
    //2.提供一个静态的公有方法,使用该方法创建一个对象的实例
    public static  Singleton getInstance(){
        if(instance ==null){
            instance = new Singleton();
        }
        return instance;
    }
}

 public static void main(String[] args) {
        //测试
        System.out.println("这是懒汉式,线程不安全");
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        //调用两个方法获取的对象实例,是相同的
        System.out.println(instance==instance1);
        //获取两个实例的hashcode
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());
    }
这是懒汉式,线程不安全
true
1956725890
1956725890
3、内部静态类的方法:

结合了懒汉式和饿汉式的各自的优点,真正需要对象的时候才会加载,加载类是线程安全的。

class  Singleton {
    private static volatile Singleton instance;
    //1.私有化构造器
    private Singleton() {
    }
    //写一个静态内部类,该类中有一个静态的属性,Singleton
    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }
    //2.提供一个静态的公有方法,直接返回SingletonInstance.INSTANCE
    //synchronized关键字
    public static synchronized Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

4、枚举单例:

使用枚举实现单例模式,实现简单,调用率高,枚举的本身就是一个单例模式,由JVM从根本上提供保障。

package com.lijie;

//使用枚举实现单例模式 优点:实现简单、枚举本身就是单例,由jvm从根本上提供保障!避免通过反射和反序列化的漏洞 缺点没有延迟加载
public class Type08 {
  
enum  Singleton{
    INSTANCE;//属性
    public  void  Say(){
        System.out.println("hello");
    }
}
    public static void main(String[] args) {
        Singleton instacne = Singleton.INSTANCE;
        Singleton instacne2 = Singleton.INSTANCE;

        System.out.println(instacne == instacne2);
        System.out.println(instacne.hashCode());
        System.out.println(instacne2.hashCode());
        instacne.Say();
    }
}
5、通过双重锁检测创建
public class Singleton {
     //先创建实例,步初始化
    private static Singleton instance;

    private Singleton() {
        System.out.println("这是私有化构造器创建的实例");
    }

    public static Singleton getInstance(){
        if(instance == null){
            synchronized (Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
    public static void main(String[] args) {
           Singleton s1 = Singleton.getInstance();
           Singleton s2 = Singleton.getInstance();
           System.out.println(s1 == s2);
    }
}
2、工厂模式?

1、它提供了一种创建对象的最佳方式。
2、在工厂模式中通过使用一个共同的接口来指向新创建的对象。实现了创建者和调用者分离。
工厂模式分为简单工厂、工厂方法、抽象工厂模式
简单工厂 :用来生产同一等级结构中的任意产品。
工厂方法 :用来生产同一等级结构中的固定产品。
抽象工厂 :用来生产不同产品族的全部产品。

优点:简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。明确区分了各自的职责和权力,有利于整个软件体系结构的优化。

缺点:很明显工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则

1、 简单工厂:
//首先创建一个图形类的公共接口
public interface Shape {
    void draw();
}
//创建接口的一个具体的实现类,长方形
public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Inside Rectangle::draw() method.");
    }
}
//正方形类
public class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("Inside Square::draw() method.");
    }
}
//圆的类
public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Inside Circle::draw() method.");
    }
}
//实现一个创建图形的工厂
public class ShapeFactory {

    //使用 getShape 方法获取形状类型的对象
    public Shape getShape(String shapeType) {
        if (shapeType == null) {
            return null;
        }
        shapeType = shapeType.toLowerCase(); //将字符串所有的大写转换为小写
        switch (shapeType) {
            case "circle":
                return new Circle();
            case "rectangle":
                return new Rectangle();
            case "square":
                return new Square();
            default:
                return null;
        }
    }
}
2、工厂方法:

工厂方法中,工厂不再实现具体产品的创建,而是将产品创建的具体操作交给了子类,工厂只要提供一个子类工厂继承的接口,实现具体创建方法就可以。

package com.lijie;
public interface Car {
	public void run();
}
public interface CarFactory {
	Car createCar();
}
public class AoDi implements Car {
	public void run() {
		System.out.println("我是奥迪汽车..");
	}
}
public class Bmw implements Car {
	public void run() {
		System.out.println("我是宝马汽车...");
	}
}
public class AoDiFactory implements CarFactory {
	public Car createCar() {
		return new AoDi();
	}
}
public class BmwFactory implements CarFactory {
	public Car createCar() {
		return new Bmw();
	}
}
public class Client {
	public static void main(String[] args) {
		Car aodi = new AoDiFactory().createCar();
		Car jili = new BmwFactory().createCar();
		aodi.run();
		jili.run();
	}
}

3、抽象工厂模式

简单来说就是工厂的工厂,可以通过抽象工厂创建具体工厂,然后再由具体工厂实现具体产品的创建

//首先创建一个汽车工厂接口
public interface Car {
	   void run();
}
//实现一个汽车工厂接口的子类
 class CarA implements Car{
	public void run() {
		System.out.println("宝马");
	}
}
//实现另一个汽车工厂的子类
 class CarB implements Car{
	public void run() {
		System.out.println("摩拜");
	}
}
//创建一个发动机工厂的接口
public interface Engine {
    void run();
}
//实现一个发动机工厂的子类
class EngineA implements Engine {
    public void run() {
        System.out.println("转的快!");
    }
}
//实现另一个发动机工厂的子类
class EngineB implements Engine {
    public void run() {
        System.out.println("转的慢!");
    }
}
//实现一个抽象工厂,也就是普通工厂的工厂
public interface TotalFactory {
	// 创建汽车
	Car createChair();
	// 创建发动机
	Engine createEngine();
}

//总工厂实现类,由他决定调用哪个工厂的那个实例
class TotalFactoryReally implements TotalFactory {
	public Engine createEngine() {
		return new EngineA();
	}
	public Car createChar() {
		return new CarA();
	}
}
public class Test {

    public static void main(String[] args) {
        TotalFactory totalFactory2 = new TotalFactoryReally();
        Car car = totalFactory2.createChar();
        car.run();

        TotalFactory totalFactory = new TotalFactoryReally();
        Engine engine = totalFactory.createEngine();
        engine.run();
    }
}
1、代理模式 1.1静态代理
  • 静态代理:由程序员创建,也就是在编译时就将接口、被代理类、代理类等确定下来,在程序运行之前,代理类.class文件以及生成。
  • 它主要就是有一个公共的接口、一个被代理类,以及一个代理类,这两个类都实现了这个接口,这个公共的接口定义了被代理类的一个行为规范,代理类持有被代理类的具体实现方法,而且代理类还可以在执行被代理类的方法之前添加额外的行为,这就是代理模式的一个很大的优点,体现最直白的地方就是SpringAOP(面向切面编程),我们可以在切点之前和之后都添加一些操作,而这些切点就是一些方法,而这些方法所在的类就是被代理的,这也是面向编程的主要思想。
  • 示例:
public interface Image {
   void display();
}
public class RealImage implements Image {
   private String fileName;
   
   public RealImage(String fileName) {
       this.fileName = fileName;
       loadFromDisk(fileName);
  }
   @Override
   public void display() {
       System.out.println("Displaying " + fileName);
  }
   private void loadFromDisk(String fileName) {
       System.out.println("Loading " + fileName);
  }
}
public class ProxyImage implements Image {

   private RealImage realImage;

   private String fileName;

   public ProxyImage(String fileName) {
       this.fileName = fileName;
  }

   @Override
   public void display() {
       if (realImage == null) {
           realImage = new RealImage(fileName);
      }
       realImage.display();
  }
}
public class ProxyPatternDemo {

   public static void main(String[] args) {
       Image image = new ProxyImage("test.png");

       //图像将从磁盘加载
       image.display();
       System.out.println("");

       //图像将无法从磁盘加载
       image.display();
  }

}
1.2动态代理

动态代理的两个核心部分:

  • Proxy类:主要是通过这个类的一个静态方法创建一个代理类的实例,这个方法中传入三个参数,第一个是继承了invocationHandler接口实现类的类加载器;第二个是代理对象的实现的接口;invocationHandler实现类的实例对象。这样就可以返回一个代理类接口的对象,注意:这个类代理的是接口不是类,最后强转之后是一个接口类型的代理对象
  • invocationHandler接口:这个接口中传入一个被代理对象的target,以及存在一个invoke()方法,这个方法主要执行被代理对象的所有方法,如果代理对象需要执行一些自己的操作就可以再invoke()方法的前后进行执行,这个invoke就好比是一个切面,AOP就是这个原理。
    代码示例:
public interface Rent {
//被代理类需要实现发接口,里面有具体实现的方法。
    void rent();
    void fare();
}
public class Host  implements Rent {
   //实现接口的被被代理类,此处是房东
    public Host() {
    }
    @Override
    public void rent() {
        System.out.println("房东想要租房子");
    }

    @Override
    public void fare() {
        System.out.println("收房租。。。");
    }
}
public class MonitorUtil  {
      //一个简单的时间工具类,可以返回一个方法执行的时间。
    private static ThreadLocal t1 = new ThreadLocal<>();

    public static void start(){
        t1.set(System.currentTimeMillis());
    }
    
    public static void finish(String methodName){
        long finishTime  = System.currentTimeMillis();
        System.out.println("执行方法"+ methodName +"耗时:" + (finishTime-t1.get()) + "ms");
    }
}
public class ProxyInvocationHandler implements InvocationHandler {
     //传入的被代理类目标
    private Object target;
     //获取被代理类的一个方法

    public ProxyInvocationHandler(Object target) {
        this.target = target;
    }
     //invoke核心方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        MonitorUtil.start();//方法执行的开始时间
        //方法执行后返回一个结果result
        Object result = method.invoke(target, args);
        method(method.getName());
        MonitorUtil.finish(method.getName());//方法执行的结束时间
        return result;
    }
     //代理类可以自己执行的一些操作,这里指的是中介收取中介费
    public void method(String name){
        System.out.println(name + "方法执行了");
    }
}
public class Cilent {

    public static void main(String[] args) {
        //首先创建被代理类的对象,以便于对
        Host host = new Host();
       //创建invocatioinHandler实现类的对象,构造器中传入目标对象
        ProxyInvocationHandler phi = new ProxyInvocationHandler(host);
        //通过代理类的newProxyInstance方法获得一个代理类的实例,强转为目标接口类
        Rent proxy = (Rent) Proxy.newProxyInstance(phi.getClass().getClassLoader(), host.getClass().getInterfaces(), phi);
        //可以通过代理类实现操作
        proxy.rent();
        proxy.fare();
    }
}
房东想要租房子
rent方法执行了
执行方法rent耗时:0ms
收房租。。。
fare方法执行了
执行方法fare耗时:0ms
3、观察者模式
  • 对象之间存在着一对多的关系,那就使用观察者模式,比如当一个对象被修改的时候,可以自动通知它依赖的对象做出相对应的更新修改。
  • 一般来说观察者模式主要有三各类,Subject(主题类),Observe抽象类(观察类),Cilent(客户端),Subject类主要实现存储观察者的一个ArrayList,将观察者添加到观察列表中的方法attach(),以及通知所有观察者的方法notifyAllObserve()方法。以及状态的修改方法setStatue()。
  • 示例:
public class Subject {
       //首先是一个添加观察者的列表
    private List observers = new ArrayList<>();
      //一个状态值,状态改变那么就通知其他的观察者改变
    private int state;
    
    public int getState() {
        return state;
    }
    public void setState(int state) {
        this.state = state;
        notifyAllObservers();
    }
    //添加到观察者列表之中
    public void attach(Observer observer) {
        observers.add(observer);
    }
    //通知所有的观察者去自动更新
    public void notifyAllObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

//抽象的观察者方法,以便于观察者实现
public abstract class Observer {

    protected Subject subject;

    public abstract void update();

}
//创建多个实体类观察者,实现更新方法
public class BinaryObserver extends Observer {

    public BinaryObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println("Binary String: "
                + Integer.toBinaryString(subject.getState()));
    }
}

public class OctalObserver extends Observer {

    public OctalObserver(Subject subject){
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println( "Octal String: "
                + Integer.toOctalString( subject.getState() ) );
    }

}
public class HexaObserver extends Observer {

    public HexaObserver(Subject subject){
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println( "Hex String: "
                + Integer.toHexString( subject.getState() ).toUpperCase() );
    }

}
public class ObserverPatternDemo {

    public static void main(String[] args) {
        Subject subject = new Subject();

        new BinaryObserver(subject);
        new HexaObserver(subject);
        new OctalObserver(subject);

        System.out.println("First state change: 15");
        subject.setState(15);
        System.out.println();

        System.out.println("Second state change: 10");
        subject.setState(10);
    }
}
First state change: 15
Binary String: 1111
Hex String: F
Octal String: 17

Second state change: 10
Binary String: 1010
Hex String: A
Octal String: 12

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/285642.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号