前言
- Java的设计模式在面试时也会经常问到,他总共有23种设计模式,设计模式就是解决问题的方案,也是一种编码思想。
- Java的设计模式主要分为三类:
- 创建型模式
共五种:工厂(简单工厂(工厂方法模式)、抽象工厂模式)、单例模式、建造者模式、原型模式。 - 结构型模式
共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 - 行为型模式
共十一种:策略模式、模板方法模式、观察者模式(监听器)、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
- 一般情况下工厂模式的以Factory结尾;工具类通常使用单例模式,以Util结尾;建造者模式通常以Builder结尾;适配器模式通常以Adapter结尾;装饰器模式通常以Decorator结尾。
- 常用到的设计模式其实也不多。
单例模式
- 单例模式就是一个类只有一个实例
- 单例模式分为饿汉模式和懒汉模式
- 枚举是饿汉式的单例模式
饿汉式
- 类加载时就创建实例。
- 满足饿汉的单例模式有以下几个条件
- 不能让调用者创建:构造方法私有化
- 给调用者提供对象并且调用者不能创建对象:声明方法返回对象并且方法是静态方法
- 返回的对象是同一个并且类加载时就创建:声明字段创建对象,并且使用static final 修饰,并且赋初始值(静态方法可以调用多次,返回的对象就不是同一个了,对象不能修改,所以用final修饰,静态方法中返回值得是静态的,所以用static修饰)
- 饿汉模式是不用考虑线程并发安全问题的,因为static修饰的是在类加载的时候加载,JVM在类加载时,只会加载一次,所以实例也只会创建一次,并且实例用final修饰,一旦赋值就不能改变,所以从始至终类的实例只会有一个。
public class Student {
public static final Student student = new Student();
private Student(){}
public static Student getInstance(){
return student;
}
}
Student instance = Student.getInstance();
Student instance1 = Student.getInstance();
System.out.println(instance1.hashCode());
System.out.println(instance.hashCode());
懒汉式
- 使用的时候才创建实例
- 懒汉式满足的条件:
- 不能让调用者创建:构造方法私有化
- 给调用者提供对象并且调用者不能创建对象:声明方法返回对象并且方法是静态方法
- 返回的对象是同一个:声明字段创建对象,使用static修饰
- 使用实例的时候才创建:声明字段创建对象时不能用final修饰,并且初始值赋为null(final修饰后一旦赋值就不可更改,使用实例时就不能赋值了)
- 使用实例的时候判断没有实例才创建:双重判断加同步代码块判断是否已经有实例
- 版本一:
- 如果多个线程同时进入判断,比如线程1来的时候employee为空,满足条件就给employee赋值,当线程1还没给employee赋值成功时,线程2来了,判读employee还是为空,线程2也给employee赋值,那么就有多个Employee的实例了。
public class Employee {
public static Employee employee = null;
private Employee(){}
public static Employee getInstance(){
if(employee == null){
employee = new Employee();
}
return employee;
}
}
- 版本二
- employee赋值时候使用同步代码块,并且同步锁要是全局的,所以用字节码对象
- 这样还是会有问题:
- 并发情况下,多个线程都满足employee为空(假设线程1 和线程2 都满足),然后尝试获取锁,线程1获取到了锁,然后给employee赋值并释放锁;线程2获取到了锁,又去给employee赋值,那么又会出现多个实例
public class Employee {
public static Employee employee = null;
private Employee(){}
public static Employee getInstance(){
if(employee == null){
synchronized (Employee.class){
employee = new Employee();
}
}
return employee;
}
}
public class Employee {
public static Employee employee = null;
private Employee(){}
public static Employee getInstance(){
if(employee == null){
synchronized (Employee.class){
if(employee == null){
employee = new Employee();
}
}
}
return employee;
}
}
枚举
- 枚举的构造器默认私有化的,为枚举类定义一个实例就是单例
enum Teacher {
INSTANCE;
}
Teacher.INSTANCE
装饰者模式
- 对原有功能进行增强
- 装饰者模式的实现步骤
- 增强类继承原始类
- 增强类提供无参构造方法
- 增强类提供原有类的属性和参数为原有类的构造方法
- 增强类重写原有类要增强的方法
public class Target {
public Boolean isEmpty(String str){
return str == null;
}
}
public class TargetDecorate extends Target {
private Target target;
public TargetDecorate(){
}
public TargetDecorate(Target target){
this.target = target;
}
@Override
public Boolean isEmpty(String str) {
Boolean empty = target.isEmpty(str);
if(!empty){
return "".equals(str);
}
return empty;
}
}
@Test
public void test1(){
TargetDecorate targetDecorate = new TargetDecorate(new Target());
System.out.println(targetDecorate.isEmpty(""));
}
工厂模式
简单工厂
public interface IPhone {
void call();
}
public class Huawei implements IPhone{
@Override
public void call(){
System.out.println("华为");
}
}
public class Xiaomi implements IPhone{
@Override
public void call(){
System.out.println("小米");
}
}
public class PhoneFactory {
public IPhone getPhone(String type){
if("huawei".equals(type)){
return new Huawei();
}else if("xiaomi".equals(type)){
return new Xiaomi();
}
return null;
}
}
public class PhoneFactory {
public static ConcurrentHashMap<String,IPhone> hashMap = new ConcurrentHashMap();
static{
initHashMap();
}
private static void initHashMap(){
hashMap.put("huawei",new Huawei());
hashMap.put("xiaomi",new Xiaomi());
}
public IPhone getPhone(String type){
return hashMap.get(type);
}
}
@Test
public void test2(){
PhoneFactory phoneFactory = new PhoneFactory();
IPhone xiaomi = phoneFactory.getPhone("xiaomi");
IPhone huawei = phoneFactory.getPhone("huawei");
xiaomi.call();
huawei.call();
}
工厂方法
- 每个工厂实现抽象工厂,每个产品实现抽象产品,一个工厂创建一个品牌的产品。
public interface IPhone {
void call();
}
public interface IPhoneFactory {
IPhone getPhone();
}
public class Huawei implements IPhone {
@Override
public void call(){
System.out.println("华为");
}
}
public class Xiaomi implements IPhone {
@Override
public void call(){
System.out.println("小米");
}
}
public class HaweiFactory implements IPhoneFactory{
@Override
public Huawei getPhone(){
return new Huawei();
}
}
public class XiaomiFactory implements IPhoneFactory {
@Override
public Xiaomi getPhone() {
return new Xiaomi();
}
}
@Test
public void test3(){
Xiaomi xiaomi = new XiaomiFactory().getPhone();
xiaomi.call();
Huawei huawei = new HaweiFactory().getPhone();
huawei.call();
}
抽象工厂
- 抽象工厂中可以生产不同的产品,每个工厂创建同一品牌的不同产品,不能生产的直接返回null.
public interface IPad {
public void tv();
}
public interface IPhone {
void call();
}
public interface IFactory {
IPhone getPhone();
IPad getPad();
}
public class HuaweiPhone implements IPhone {
@Override
public void call() {
System.out.println("华为");
}
}
public class HuaweiPad implements IPad {
@Override
public void tv() {
System.out.println("华为的pad");
}
}
public class XiaomiPhone implements IPhone {
@Override
public void call(){
System.out.println("小米");
}
}
public class HaweiFactory implements IFactory {
@Override
public HuaweiPhone getPhone(){
return new HuaweiPhone();
}
@Override
public IPad getPad() {
return new HuaweiPad();
}
}
public class XiaomiFactory implements IFactory{
@Override
public IPhone getPhone() {
return new XiaomiPhone();
}
@Override
public IPad getPad() {
return null;
}
}
@Test
public void test4(){
IPad huaweiPad = new HaweiFactory().getPad();
huaweiPad.tv();
IPhone huaweiPhone = new HaweiFactory().getPhone();
huaweiPhone.call();
IPhone xiaomiPhone = new XiaomiFactory().getPhone();
xiaomiPhone.call();
IPad xiaomiPad = new XiaomiFactory().getPad();
xiaomiPad.tv();
}
模版模式
- 在一个方法中定义了一个算法的骨架,允许子类在不改变算法结构的情况下重定义某些步骤的具体内容。模板方法模式通常用于实现一个算法的不变部分,而将可变的行为留给子类来实现。
- Spring的容器刷新就是用的模版模式
- 其实就是一个抽象类里面定义类模版方法,这个模版方法按照一定次序调用了很多这个类的抽象方法,使用这个模版的类就要继承这个模版类,必须实现它的抽象方法,也就是模版中的内容自己定义,模版只是定义了框架和顺序。
public abstract class FoodPreparer {
public void prepareFood() {
prepareIngredients();
cook();
serve();
}
public abstract void prepareIngredients();
public abstract void cook();
public abstract void serve();
}
public class PastaPreparer extends FoodPreparer {
@Override
public void prepareIngredients() {
System.out.println("Preparing pasta ingredients.");
}
@Override
public void cook() {
System.out.println("Cooking pasta.");
}
@Override
public void serve() {
System.out.println("Serving pasta.");
}
}
public class PizzaPreparer extends FoodPreparer {
@Override
public void prepareIngredients() {
System.out.println("Preparing pizza ingredients.");
}
@Override
public void cook() {
System.out.println("Baking pizza.");
}
@Override
public void serve() {
System.out.println("Serving pizza.");
}
}
@Test
public void test() throws Exception{
FoodPreparer pastaPreparer = new PastaPreparer();
pastaPreparer.prepareFood();
System.out.println("======================");
FoodPreparer pizzaPreparer = new PizzaPreparer();
pizzaPreparer.prepareFood();
}
适配器模式
- 用于解决接口不兼容的问题,使得原本没有任何关系的接口可以协同工作
- 下面的例子是美国插头适配中国插座的例子
public interface ChineseSocket {
void plugIn();
}
public class AmericanPlug {
public void connect() {
System.out.println("美国插头已连接。");
}
}
public class PowerAdaptor extends AmericanPlug implements ChineseSocket {
public void plugIn() {
System.out.println("美国插头正在适配到中国插座...");
connect();
System.out.println("美国插头已成功适配到中国插座。");
}
}
@Test
public void test(){
ChineseSocket chineseSocket = new PowerAdaptor();
chineseSocket.plugIn();
}
代理模式
- 客户端并不直接调用实际的对象,而是通过调用代理对象,来间接的调用实际的对象,相当于经纪人。
- 代理分为静态代理和动态代理。
- 代理可以增加在原业务的基础上增加功能。
静态代理
public interface ISongHua {
void songHua();
}
public class XiaoMing implements ISongHua{
@Override
public void songHua() {
System.out.println("小明送花给小兰");
}
}
public class XiaoMingProxy implements ISongHua{
private XiaoMing xiaoMing;
public XiaoMingProxy() {
}
public XiaoMingProxy(XiaoMing xiaoMing) {
this.xiaoMing = xiaoMing;
}
@Override
public void songHua() {
System.out.println("送花之前的逻辑");
xiaoMing.songHua();
System.out.println("送花之后的逻辑");
}
}
@Test
public void SongHuaTest(){
new XiaoMingProxy(new XiaoMing()).songHua();
}
送花之前的逻辑
小明送花给小兰
送花之后的逻辑
动态代理
- 动态代理分为jdk动态代理和cglib动态代理
- jdk动态代理只能代理实现了接口的类(如上述的XiaoMing),cglib动态代理能代理没有实现接口的类,默认是jdk动态代理
JDK动态代理
- jdk代理中主要有java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口
- 代理类和被代理类会实现同一个接口,只是这里是隐式的,是在JVM 在运行时动态生成的。
- InvocationHandler中的invoke方法用来处理被代理类方法,对被代理类的方法进行增强
- Proxy的静态方法newProxyInstance用来动态生成代理类,代理类实现了目标对象所实现的接口,并将方法调用委托给 InvocationHandler
代理类
的名字通常是$Proxy后加上一个数字
interface Hello {
void sayHello();
}
public class SimpleHello implements Hello{
@Override
public void sayHello() {
System.out.println("Hello, world!");
}
}
public class HelloInvocationHandler implements InvocationHandler {
private Object target;
public HelloInvocationHandler(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);
System.out.println("方法执行后的操作");
return result;
}
}
@Test
public void JdkTest() {
SimpleHello hello = new SimpleHello();
InvocationHandler handler = new HelloInvocationHandler(hello);
ClassLoader classLoader = hello.getClass().getClassLoader();
Class<?>[] interfaces = hello.getClass().getInterfaces();
Hello proxy = (Hello) Proxy.newProxyInstance(classLoader, interfaces, handler);
proxy.sayHello();
}
CGLIB动态代理
- org.springframework.cglib.proxy.Enhancer类,org.springframework.cglib.proxy.MethodInterceptor接口,
- org.springframework.cglib.proxy.MethodProxy类
- Enhancer类创建代理类
- MethodInterceptor拦截方法,做方法增强
- MethodProxy是Java反射中 Method 类的一个补充。它提供了一种更高效的方式来调用方法
public class HelloTarget {
public void sayHello(String name) {
System.out.println("Hello, " + name + "!");
}
}
public class SimpleInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("目标方法执行前操作");
Object result = proxy.invokeSuper(obj, args);
System.out.println("目标方法执行后操作");
return result;
}
}
@Test
public void CglibTest() throws Exception{
HelloTarget target = new HelloTarget();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HelloTarget.class);
enhancer.setCallback(new SimpleInterceptor());
HelloTarget proxy = (HelloTarget) enhancer.create();
proxy.sayHello("World");
}
策略模式
- 它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
- 策略模式一般情况下都是用来优化if-else语句的
- 简单工厂中用ConcurrentHashMap改良就是策略模式
public interface PaymentStrategy {
public double pay(double money);
}
public class CashPayment implements PaymentStrategy {
@Override
public double pay(double money) {
System.out.println("Cash Payment of " + money);
return money;
}
}
public class CardPayment implements PaymentStrategy {
@Override
public double pay(double money) {
System.out.println("Card Payment of " + money);
return money - money * 0.02;
}
}
public class PaymentContext {
private PaymentStrategy strategy;
public PaymentContext(PaymentStrategy strategy){
this.strategy = strategy;
}
public double executePayment(double money){
return this.strategy.pay(money);
}
}
@Test
public void strategyTest(){
PaymentContext paymentContext = new PaymentContext(new CashPayment());
System.out.println("Cash Payment: " + paymentContext.executePayment(100));
paymentContext = new PaymentContext(new CardPayment());
System.out.println("Card Payment: " + paymentContext.executePayment(100));
}