八个常见面试问到的设计模式结合spring或java类库进行分析,并提供简单的java实现——单例、工厂、适配、装饰、代理、迭代器、观察者、责任链

创建型

1、单例模式

单例模式确保一个类只有一个实例。

单例模式可以有多种实现,其中分为懒汉式和饿汉式。

懒汉式指的是直到使用时才进行实例化,例如spring的BeanFactory就是使用懒汉式加载,好处就是可以节省资源,更快的启动。但是它是线程不安全的,不安全之处体现在它可能会被多次实例化,因此实现方式可以是枚举、静态内部类、双重校验锁等。其中枚举可以防止反射攻击。

饿汉式指的是直接在应用启动时就将其实例化,很显然是线程安全的。例如在spring中的applicationContext中就是用饿汉式加载bean的。

枚举实现

package DesignPattern.Singleton;

public enum Singleton {//枚举实现

    INSTANCE;

    private String objName;


    public String getObjName() {
        return objName;
    }


    public void setObjName(String objName) {
        this.objName = objName;
    }


    public static void main(String[] args) {

        // 单例测试
        Singleton firstSingleton = Singleton.INSTANCE;
        firstSingleton.setObjName("firstName");
        System.out.println(firstSingleton.getObjName());
        Singleton secondSingleton = Singleton.INSTANCE;
        secondSingleton.setObjName("secondName");
        System.out.println(firstSingleton.getObjName());
        System.out.println(secondSingleton.getObjName());

        // 反射获取实例测试
        try {
            Singleton[] enumConstants = Singleton.class.getEnumConstants();
            for (Singleton enumConstant : enumConstants) {
                System.out.println(enumConstant.getObjName());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

双重校验锁

package DesignPattern.Singleton;

/**
 * uniqueInstance 只需要被实例化一次,之后就可以直接使用了。
 * 加锁操作只需要对实例化那部分的代码进行,只有当 uniqueInstance 没有被实例化时,才需要进行加锁。
 *
 * 双重校验锁先判断 uniqueInstance 是否已经被实例化,如果没有被实例化,那么才对实例化语句进行加锁。
 */
public class DoubleTestSync {

    private volatile static DoubleTestSync uniqueInstance;

    private DoubleTestSync() {
    }


    public static DoubleTestSync getUniqueInstance() {
        if (uniqueInstance == null) {
            synchronized (DoubleTestSync.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new DoubleTestSync();
                }
            }
        }
        return uniqueInstance;
    }

    /**
     * 考虑下面的实现,也就是只使用了一个 if 语句。在 uniqueInstance == null 的情况下,
     * 如果两个线程都执行了 if 语句,那么两个线程都会进入 if 语句块内。
     * 虽然在 if 语句块内有加锁操作,但是两个线程都会执行 uniqueInstance = new Singleton();
     * 这条语句,只是先后的问题,那么就会进行两次实例化。因此必须使用双重校验锁,
     * 也就是需要使用两个 if 语句:第一个 if 语句用来避免 uniqueInstance 已经被实例化之后的加锁操作,
     * 而第二个 if 语句进行了加锁,
     * 所以只能有一个线程进入,就不会出现 uniqueInstance == null 时两个线程同时进行实例化操作。
     */
/*
    if (uniqueInstance == null) {
        synchronized (Singleton.class) {
            uniqueInstance = new Singleton();
        }
    }
*/

}

 

2、工厂模式

工厂模式又分为三种——简单工厂、工厂方法、抽象工厂

工厂方法又可以拆分为实例工厂方法和静态工厂方法,静态工厂方法就是将工厂变成静态的,并不需要将其实例化。

简单工厂

简单工厂把实例化的操作单独放到一个类中,这个类就是简单工厂类,让简单工厂类来决定应该实例化哪个子类。

这样客户类就可以实现与具体子类的解耦。


public interface Product {
}

//------------------------------------------------------------------

public class ConcreteProduct2 implements Product {
    {
        System.out.println(ConcreteProduct2.class.getName());
    }
}

//------------------------------------------------------------------

public class ConcreteProduct1 implements Product {
    {
        System.out.println(ConcreteProduct1.class.getName());
    }
}

//------------------------------------------------------------------

public class SimpleFactory {
    public Product createProduct(int type) {
        if (type == 1) {
            return new ConcreteProduct1();
        } else if (type == 2) {
            return new ConcreteProduct2();
        }
        return new ConcreteProduct();
    }
}

//------------------------------------------------------------------

public class Client {
    public static void main(String[] args) {
        SimpleFactory simpleFactory = new SimpleFactory();
        Product product = simpleFactory.createProduct(1);
        // do something with the product
    }
}

工厂方法

工厂方法和简单工厂的区别在于:

简单工厂是由另一个类来创建对象,所谓的另一个类,指的是和要创建的对象完全无关的一个类,类似于switch的作用。

而工厂方法则是交由一个抽象的工厂类(注意这里不是抽象工厂)的子类来实例化对象。

public interface Product {}

public class ConcreteProduct implements Product{}
public class ConcreteProduct1 implements Product {}
public class ConcreteProduct2 implements Product {}


public abstract class Factory {
    abstract public Product factoryMethod();

    public void doSomething() {
        Product product = factoryMethod();
        // do something with the product
    }
}

public class ConcreteFactory extends Factory {
    public Product factoryMethod() {
        System.out.println(this.getClass().getName());
        return new ConcreteProduct();
    }
}

public class ConcreteFactory1 extends Factory {
    public Product factoryMethod() {
        System.out.println(this.getClass().getName());
        return new ConcreteProduct1();
    }
}

public class ConcreteFactory2 extends Factory {
    public Product factoryMethod() {
        System.out.println(this.getClass().getName());
        return new ConcreteProduct2();
    }
}

/**
 * 在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。
 *
 * Factory 有一个 doSomething() 方法,这个方法需要用到一个产品对象,
 * 这个产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。
 */
public class Client {
    public static void main(String[] args) {
        Product product = new ConcreteFactory().factoryMethod();
        Product concreteProduct1 = new ConcreteFactory1().factoryMethod();
        Product concreteProduct2 = new ConcreteFactory2().factoryMethod();
    }
}

抽象工厂

抽象工厂创建出来的对象会是一堆相关联的对象,这些对象是相关的,换句话说,这些对象必须要一起被创建出来,而工厂方法只需要创建出一个对象。

但是抽象工厂模式内部使用到了工厂方法模式,具体看下面的实现。

public class AbstractProductA {}
public class ProductA1 extends AbstractProductA {}
public class ProductA2 extends AbstractProductA {}

//-------------------------------------------------------------

public class AbstractProductB {}
public class ProductB1 extends AbstractProductB {}
public class ProductB2 extends AbstractProductB {}

//-------------------------------------------------------------

public abstract class AbstractFactory {
    abstract AbstractProductA createProductA();
    abstract AbstractProductB createProductB();
}

//-------------------------------------------------------------

public class ConcreteFactory1 extends AbstractFactory {
    AbstractProductA createProductA() {
        System.out.println(ProductA1.class.getName());
        return new ProductA1();
    }

    AbstractProductB createProductB() {
        System.out.println(ProductB1.class.getName());
        return new ProductB1();
    }
}

//-------------------------------------------------------------

public class ConcreteFactory2 extends AbstractFactory {
    AbstractProductA createProductA() {
        System.out.println(ProductA2.class.getName());
        return new ProductA2();
    }

    AbstractProductB createProductB() {
        System.out.println(ProductA2.class.getName());
        return new ProductB2();
    }
}

//-------------------------------------------------------------

/**
 * 抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,
 * 并且这些对象是相关的,也就是说必须一起创建出来。
 * 而工厂方法模式只是用于创建一个对象,这和抽象工厂模式有很大不同。
 *
 * 抽象工厂模式用到了工厂方法模式来创建单一对象,
 * AbstractFactory 中的 createProductA() 和 createProductB() 方法都是让子类来实现,
 * 这两个方法单独来看就是在创建一个对象,
 * 这符合工厂方法模式的定义。
 *
 * 至于创建对象的家族这一概念是在 Client 体现,
 * Client 要通过 AbstractFactory 同时调用两个方法来创建出两个对象,
 * 在这里这两个对象就有很大的相关性,Client 需要同时创建出这两个对象。
 *
 * 从高层次来看,抽象工厂使用了组合,
 * 即 Cilent 组合了 AbstractFactory,
 * 而工厂方法模式使用了继承。
 */
public class Client {
    public static void main(String[] args) {
        AbstractFactory abstractFactory1 = new ConcreteFactory1();
        AbstractProductA productA1 = abstractFactory1.createProductA();
        AbstractProductB productB1 = abstractFactory1.createProductB();

        AbstractFactory abstractFactory2 = new ConcreteFactory2();
        AbstractProductA productA2 = abstractFactory2.createProductA();
        AbstractProductB productB2 = abstractFactory2.createProductB();
        // do something with productA and productB
    }

 

结构型

1、适配器模式

简而言之,适配器模式就是将一个类接口转换成另一个用户需要的接口。

在springMVC中也有使用到适配器模式,例如HandlerAdapter。

为什么springMVC要使用适配器模式呢,原因是这样能更加易于扩展。

很显然,handler可以有多种实现,例如实现HttpRequestHandler接口或者实现Controller接口。

在一个controller可以有多种实现的情况下,如果没有适配器模式,则需要用到大量的if else来判断究竟是实现了哪一种,当我们要添加一种新的实现的时候,就需要修改原先的if else代码,这违反了开闭原则。

因此引入了适配器模式,这样,我们在添加新的实现时,只需要再实现一个新的适配器即可。

public interface Duck {
    void quack();
}

//--------------------------------------------

public interface Turkey {
    void gobble();
}

//--------------------------------------------

public class WildTurkey implements Turkey {
    @Override
    public void gobble() {
        System.out.println("gobble!");
    }
}

//--------------------------------------------

public class TurkeyAdapter implements Duck {
    Turkey turkey;

    public TurkeyAdapter(Turkey turkey) {
        this.turkey = turkey;
    }

    @Override
    public void quack() {
        turkey.gobble();
    }
}

//--------------------------------------------

public class Client {
    public static void main(String[] args) {
        Turkey turkey = new WildTurkey();
        Duck duck = new TurkeyAdapter(turkey);
        duck.quack();
    }
}

2、装饰者模式

在Java的IO流中,也运用到了装饰者模式。

Java中一些IO流有一个有参的构造方法,例如BufferedInputStream,它的构造方法需要提供一个InputStream的子类

public BufferedInputStream(InputStream in) {
        this(in, DEFAULT_BUFFER_SIZE);
    }

之所以要这么做,主要是为了解决Java中没有多继承的问题,同时防止出现太多类。

简单实现如下

public interface Beverage {
    double cost();
}

//------------------------------------------------------

public abstract class CondimentDecorator implements Beverage {
    protected Beverage beverage;
}

//------------------------------------------------------

public class Milk extends CondimentDecorator {

    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public double cost() {
        return 1 + beverage.cost();
    }
}

//------------------------------------------------------

public class Mocha extends CondimentDecorator {

    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }

    @Override
    public double cost() {
        return 1 + beverage.cost();
    }
}

//------------------------------------------------------

public class DarkRoast implements Beverage {
    @Override
    public double cost() {
        return 1;
    }
}

//------------------------------------------------------

public class HouseBlend implements Beverage {
    @Override
    public double cost() {
        return 1;
    }
}

//------------------------------------------------------

public class Client {

    public static void main(String[] args) {
        Beverage beverage = new HouseBlend();//选择主料
        beverage = new Mocha(beverage);//添加Mocha
        beverage = new Milk(beverage);//添加牛奶
        System.out.println(beverage.cost());

        //BufferedInputStream stream = new BufferedInputStream(new FileInputStream(new File("")));
    }
}

3、代理模式

在springAOP中,代理模式经常被使用。

简单来说,代理模式指的是一个对象的行为并不由该对象本身去执行,而是交给它的代理人去控制。

例如springAOP中的before、after等等都是由代理来完成的。

需要注意的是,jdk动态代理需要实现接口,而CGLIB则是通过继承实现,因此当被代理类被声明为final时,不能使用CGLIB。

public interface Star
{
    String sing(String name);

    String dance(String name);
}

//---------------------------------------------------------------

public class LiuDeHua implements Star
{
    @Override
    public String sing(String name)
    {
        System.out.println("给我一杯忘情水");

        return "唱完" ;
    }

    @Override
    public String dance(String name)
    {
        System.out.println("开心的马骝");

        return "跳完" ;
    }
}

//---------------------------------------------------------------

public class StarProxy implements InvocationHandler {
    // 目标类,也就是被代理对象
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 这里可以做增强
        System.out.println("收钱");

        Object result = method.invoke(target, args);

        return result;
    }

    // 生成代理类
    public Object CreatProxyedObj() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

}

//---------------------------------------------------------------

public class Client {
    public static void main(String[] args) {
        Star ldh = new LiuDeHua();//刘德华
        StarProxy proxy = new StarProxy();//创建代理对象
        proxy.setTarget(ldh);//将被代理对象set到代理对象中
        Object obj = proxy.CreatProxyedObj();//得到一个已经增强过的对象
        Star star = (Star) obj;//此时这个接口内的方法均已被增强过
        /** 控制台将会输出下面的内容
         *
         * 收钱
         * 开心的马骝
         */
        star.dance("");
    }
}

行为型

1、迭代器模式

java中有很多类都使用到了迭代器模式。

List<Integer> list = new ArrayList<Integer>();
Iterator<Integer> integerIterator = list.iterator();

简单实现如下所示

public interface Aggregate {
    Iterator createIterator();
}

//-----------------------------------------

public class ConcreteAggregate implements Aggregate {

    private Integer[] items;

    public ConcreteAggregate() {
        items = new Integer[10];
        for (int i = 0; i < items.length; i++) {
            items[i] = i;
        }
    }

    @Override
    public Iterator createIterator() {
        return new ConcreteIterator<Integer>(items);
    }
}

//-----------------------------------------

public interface Iterator<Item> {

    Item next();

    boolean hasNext();
}

//-----------------------------------------

public class ConcreteIterator<Item> implements Iterator {

    private Item[] items;
    private int position = 0;

    public ConcreteIterator(Item[] items) {
        this.items = items;
    }

    @Override
    public Object next() {
        return items[position++];
    }

    @Override
    public boolean hasNext() {
        return position < items.length;
    }
}

//-----------------------------------------

/**
 * Aggregate 是聚合类,其中 createIterator() 方法可以产生一个 Iterator;
 * Iterator 主要定义了 hasNext() 和 next() 方法。
 * Client 组合了 Aggregate,为了迭代遍历 Aggregate,也需要组合 Iterator。
 */
public class Client {

    public static void main(String[] args) {
        Aggregate aggregate = new ConcreteAggregate();
        Iterator<Integer> iterator = aggregate.createIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

2、观察者模式

spring和java中都大量使用到了这种模式。

这种模式适用于一对多的对象关系,当一个对象的状态发生改变时,就会通知所有的观察者(依赖被观察对象的对象),做出相应的反应,事件驱动机制属于观察者模式的一种实现。

public interface Subject {
    void registerObserver(Observer o);

    void removeObserver(Observer o);

    void notifyObserver();
}

//---------------------------------------------------------------------------------

/**
 * 定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
 *
 * 主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。
 */
public class WeatherData implements Subject {
    private List<Observer> observers;
    private float temperature;//温度
    private float humidity;//湿度
    private float pressure;//气压

    public WeatherData() {
        observers = new ArrayList<>();
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        notifyObserver();
    }

    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if (i >= 0) {
            observers.remove(i);
        }
    }

    @Override
    public void notifyObserver() {
        for (Observer o : observers) {
            o.update(temperature, humidity, pressure);
        }
    }
}

//---------------------------------------------------------------------------------

public interface Observer {
    void update(float temp, float humidity, float pressure);
}

//---------------------------------------------------------------------------------

public class CurrentConditionsDisplay implements Observer {

    public CurrentConditionsDisplay(Subject weatherData) {
        weatherData.registerObserver(this);
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        System.out.println("CurrentConditionsDisplay.update: " + temp + " " + humidity + " " + pressure);
    }
}

//---------------------------------------------------------------------------------

public class StatisticsDisplay implements Observer {

    public StatisticsDisplay(Subject weatherData) {
        weatherData.registerObserver(this);
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        System.out.println("StatisticsDisplay.update: " + temp + " " + humidity + " " + pressure);
    }
}

//---------------------------------------------------------------------------------

/**
 * 主题(Subject)具有注册和移除观察者、并通知所有观察者的功能,
 * 主题是通过维护一张观察者列表来实现这些操作的。
 *
 * 观察者(Observer)的注册功能需要调用主题的 registerObserver() 方法。
 */
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);

        weatherData.setMeasurements(0, 0, 0);
        weatherData.setMeasurements(1, 1, 1);
    }
}

3、责任链模式

SpringMVC的HandlerExecutionChain就属于责任链的一种实现。

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。

将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。

简单实现如下。

public enum RequestType {
    TYPE1, TYPE2
}

public class Request {

    private RequestType type;
    private String name;


    public Request(RequestType type, String name) {
        this.type = type;
        this.name = name;
    }


    public RequestType getType() {
        return type;
    }


    public String getName() {
        return name;
    }
}

//------------------------------------------------------

public abstract class Handler {

    protected Handler successor;


    public Handler(Handler successor) {
        this.successor = successor;
    }


    protected abstract void handleRequest(Request request);
}

//------------------------------------------------------------

public class ConcreteHandler1 extends Handler {

    public ConcreteHandler1(Handler successor) {
        super(successor);
    }


    @Override
    protected void handleRequest(Request request) {
        if (request.getType() == RequestType.TYPE1) {
            System.out.println(request.getName() + " is handle by ConcreteHandler1");
            return;
        }
        if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

//-------------------------------------------------------------

public class ConcreteHandler2 extends Handler {

    public ConcreteHandler2(Handler successor) {
        super(successor);
    }


    @Override
    protected void handleRequest(Request request) {
        if (request.getType() == RequestType.TYPE2) {
            System.out.println(request.getName() + " is handle by ConcreteHandler2");
            return;
        }
        if (successor != null) {
            successor.handleRequest(request);
        }
    }
}

//------------------------------------------------------------------

/**
 * 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。
 * 将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。
 */
public class Client {

    public static void main(String[] args) {

        Handler handler1 = new ConcreteHandler1(null);
        Handler handler2 = new ConcreteHandler2(handler1);

        Request request1 = new Request(RequestType.TYPE1, "request1");
        handler2.handleRequest(request1);

        Request request2 = new Request(RequestType.TYPE2, "request2");
        handler2.handleRequest(request2);
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值