EIGHT------设计模式

137 阅读8分钟

1、什么是设计模式?你都知道哪些设计模式?

设计模式一套被反复使用,为多数人知晓的代码设计经验的总结。使用设计模式的目的是为了代码重用,避免程序大量修改,同时使代码更易于理解,保证代码可靠性。
设计模式总共有 23 种,总体来说可以分为三大类:
创建型

单例模式(Singleton)、工厂模式(Fctory Method)、抽象工厂模式(Abstract Factory)...

结构型

装饰模式(Decorator)、代理模式(Proxy)、适配器模式(Adopter)...

行为型

观察者模式(Observe)

2、什么是单例模式?

简单点说,就是一个应用程序中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一般通过getInstance( )的方法来获取它们的实例。

优点:不会频繁地创建和销毁对象,浪费系统资源。

使用场景:IO 、数据库连接、Redis 连接等

单例模式写法有5种:

饿汉式 (一上来就创建对象了,如果该实例从始至终都没被使用过,则会造成内存浪费)

懒汉式(用到的时候再创建对象)

双重检测加锁DCL(直接在方法上加锁的方式在多线程环境下性能会比较低下,所以我们可以将锁的范围缩小)

静态内部类(最推荐写法)

枚举方式(最安全、简洁写法)

饿汉式\color{#008000}{饿汉式}:

public class Singleton { 
   private Singleton (){}	//将构造函数私有化,不可以通过new的方式来创建对象
   private static Singleton instance = new Singleton();  //在类的内部创建实例
   public static Singleton getInstance() {  //提供获取唯一实例的方法
     return instance;  
   }  
}

懒汉式(线程安全)\color{#008000}{懒汉式(线程安全)}:

public class Singleton {  
   private Singleton (){}  //将构造函数私有化,不可以通过new的方式来创建对象
   private static Singleton instance;  //先不创建对象,等用到的时候再创建
   public static synchronized Singleton getInstance() {  //调用到这个方法了,证明是要被用到的了
   if (instance == null) {  
       instance = new Singleton();   //如果这个对象引用为null,我们就创建并返回出去
   }  
     return instance;  
   }  
}

双重检测加锁DCLDoubleCheckedLocking\color{#008000}{双重检测加锁DCL(Double-Checked-Locking)}:

public class Singleton {  
   private Singleton (){}
   private volatile static Singleton singleton;    //volatile关键字
   public static Singleton getSingleton() {  
   if (singleton == null) {  
       synchronized (Singleton.class) {  //将锁的范围缩小,提高性能
       if (singleton == null) {  //再判断一次是否为null
           singleton = new Singleton();  
       }  
       }  
   }  
     return singleton;  
   }  
}

静态内部类\color{#008000}{静态内部类}:

public class Singleton { 
   private Singleton (){}
   private static class SingletonHolder {  //使用内部类的方式来实现加载
   	 private static final Singleton INSTANCE = new Singleton(); //创建单例对象 
   }   
   public static final Singleton getInstance() {	//获取对象
     return SingletonHolder.INSTANCE;  
   }  
}

枚举方式\color{#008000}{枚举方式}:

public enum Singleton {  //在JDK1.5中加入的enum特性[i'nju:],Enumeration
   INSTANCE;  
   public void whateverMethod() {  
   }  
}

3、什么是工厂模式?

工厂模式专门负责实例化有大量公共接口的类,本质是利用工厂方法代替New创建一种实例化对象的方式。

4、什么是简单工厂模式?

简单工厂模式又叫静态工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
(简单工厂模式中有一个抽象的接口、多个抽象接口的实现类、一个工厂类用来实例化抽象的接口)

优点:实现起来很简单,工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端不用直接创建产品对象,而仅仅“消费”产品

// 抽象产品类
abstract class Car {
   public void run();
   public void stop();
}

// 具体实现类
class Benz implements Car {
   public void run() {
       System.out.println("Benz开始启动了。。。。。");
   }
   public void stop() {
       System.out.println("Benz停车了。。。。。");
   }
}

class Ford implements Car {
   public void run() {
       System.out.println("Ford开始启动了。。。");
   }
   public void stop() {
       System.out.println("Ford停车了。。。。");
   }
}

// 工厂类
class Factory {
   public static Car getCarInstance(String type) {
       Car c = null;
       if ("Benz".equals(type)) {
           c = new Benz();
       }
       if ("Ford".equals(type)) {
           c = new Ford();
       }
       return c;
   }
}

public class Test {
   public static void main(String[] args) {
       Car c = Factory.getCarInstance("Benz");	//使用工厂模式
       if (c != null) {
           c.run();
           c.stop();
       } else {
           System.out.println("造不了这种汽车。。。");
       }
   }
}

5、什么是工厂方法模式?

不再是由一个工厂类去实例化具体的产品,而是由抽象工厂的子类去实例化产品。有四个角色:抽象工厂模式、具体工厂模式、抽象产品模式、具体产品模式。

// 抽象产品角色
public interface Moveable {
   void run();
}
// 具体产品角色
public class Plane implements Moveable {
   @Override
   public void run() {
       System.out.println("plane....");
   }
}
public class Broom implements Moveable {
   @Override
   public void run() {
       System.out.println("broom.....");
   }
}
// 抽象工厂
public abstract class VehicleFactory {
   abstract Moveable create();
}
// 具体工厂
public class PlaneFactory extends VehicleFactory {
   public Moveable create() {
       return new Plane();
   }
}
public class BroomFactory extends VehicleFactory {
   public Moveable create() {
       return new Broom();
   }
}
// 测试类
public class Test {
   public static void main(String[] args) {
       VehicleFactory factory = new BroomFactory();
       Moveable m = factory.create();
       m.run();
   }
}

6、什么是抽象工厂模式?

抽象工厂模式是在简单工厂的基础上将未来可能需要修改的代码抽象出来,通过继承的方式让子类去做决定。 与工厂方法模式不同的是,工厂方法模式中的工厂只生产单一的产品,而抽象工厂模式中的工厂生产多个产品。

//抽象工厂类
public abstract class AbstractFactory {
   public abstract Vehicle createVehicle();
   public abstract Weapon createWeapon();
   public abstract Food createFood();
}
//具体工厂类,其中Food,Vehicle,Weapon是抽象类,
public class DefaultFactory extends AbstractFactory{
   @Override
   public Food createFood() {
       return new Apple();
   }
   @Override
   public Vehicle createVehicle() {
       return new Car();
   }
   @Override
   public Weapon createWeapon() {
       return new AK47();
   }
}
//测试类
public class Test {
   public static void main(String[] args) {
       AbstractFactory f = new DefaultFactory();
       Vehicle v = f.createVehicle();
       v.run();
       Weapon w = f.createWeapon();
       w.shoot();
       Food a = f.createFood();
       a.printName();
   }
}

7、什么是装饰器模式?

装饰器模式是不改变原有类及类的继承关系情况下,动态扩展一个类的功能

优点:装饰类和被装饰类可以独立发展,不会相互耦合

8、什么是代理模式?

代理模式是指为对象提供一种通过代理的方式来访问并控制该对象行为的方法。

优点:代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度

比如买飞机票,由于离飞机场太远,直接去飞机场买票不太现实,这个时候我们就可以上携程 App 上购买飞机票,这个时候携程 App 就相当于是飞机票的代理商。

//定义售票接口
interface IAirTicket {
    void buy();
}
// 定义飞机场售票 
class AirTicket implements IAirTicket {
    @Override
    public void buy() {
        System.out.println("买票");
    }
}
//代理售票平台
class ProxyAirTicket implements IAirTicket {
    private AirTicket airTicket;
    public ProxyAirTicket() {
        airTicket = new AirTicket();
    }
    @Override
    public void buy() {
        airTicket.buy();
    }
}
//代理模式调用 
public class ProxyTest {
    public static void main(String[] args) {
        IAirTicket airTicket = new ProxyAirTicket();
        airTicket.buy();
    }
}

9、什么是观察者模式?

观察者模式是指在被观察者的状态发生变化时,系统将其状态通知到其相关依赖对象并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式。

10、什么是适配器模式

适配器模式是将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够在一起工作。
以生活中的例子来说,比如有一个充电器是 MicroUSB 接口,而手机充电口却是 TypeC 的,这个时候就需要一个把 MicroUSB 转换成 TypeC 的适配器

//传统的充电线 MicroUSB
interface MicroUSB {
    void charger();
}
//TypeC 充电口
interface ITypeC {
    void charger();
}
class TypeC implements ITypeC {
    @Override
    public void charger() {
        System.out.println("TypeC 充电");
    }
}
//适配器
class AdapterMicroUSB implements MicroUSB {
    private TypeC typeC;

    public AdapterMicroUSB(TypeC typeC) {
        this.typeC = typeC;
    }

    @Override
    public void charger() {
        typeC.charger();
    }
}
//测试调用
public class AdapterTest {
    public static void main(String[] args) {
        TypeC typeC = new TypeC();
        MicroUSB microUSB = new AdapterMicroUSB(typeC);
        microUSB.charger();

    }
}

11、简单工厂和抽象工厂有什么区别?

简单工厂模式由三种角色组成:

工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,根据逻辑不同,产生具体的工厂产品。
如例子中的Driver类。

抽象产品角色:它一般是具体产品继承的父类或者实现的接口。由接口或者抽象类来实现。如例中的Car接口。

具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现,如例子中的Benz、Bmw类。

抽象工厂模式的各个角色(和工厂方法的如出一辙):

抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。
是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。

具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
在java中它由具体的类来实现。

抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。

具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。

它和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象

12、IO 使用了什么设计模式?

IO 使用了适配器模式和装饰器模式

适配器模式:由于 InputStream 是字节流不能享受到字符流读取字符那么便捷的功能,
借助 InputStreamReader 将其转为 Reader 子类,因而可以拥有便捷操作文本文件方法;

装饰器模式:将 InputStream 字节流包装为其他流的过程就是装饰器模式,
比如,包装为 FileInputStream、ByteArrayInputStream、PipedInputStream 等。

13、Spring 中都使用了哪些设计模式?

代理模式:在 AOP 中有使用  

单例模式:bean 默认是单例模式

模板方法模式:jdbcTemplate

工厂模式:BeanFactory

观察者模式:Spring 事件驱动模型就是观察者模式很经典的一个应用,
比如,ContextStartedEvent 就是 ApplicationContext 启动后触发的事件

适配器模式:Spring MVC 中也是用到了适配器模式适配 Controller