设计模式是软件开发中针对常见问题的可重用解决方案,是最佳实践的总结。其分为3大类:
创建型模式;其关注对象创建机制,主要有单例,工厂方法,抽象工厂,建造者,原型这五种;
结构型模式:以处理类和对象的组合为主,主要有适配器,桥接,组合,装饰器,外观,享元,代理这七种;
行为型模式:主要关注对象间的通信,有责任链,命令,解释器,迭代器,中介者,备忘录,观察者,状态,策略,模板方法,访问者这11种。
但不管是哪一种设计模式,其核心目的都是为了减少代码复用,提升代码的可维护性和可扩展性,实现代码的标准化,吸收成功的经验,避免出现以前出现过的错误,实现最佳实践。本文就单例,抽象工厂,适配器,代理这四个设计模式详细展开。
单例模式是最简单设计模式之一,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象,也就是说不能使用new关键字来创建对象。其核心特性主要有3:
public class EagerSingleton {//饿汉式
// 类加载时就初始化
private static final EagerSingleton INSTANCE = new EagerSingleton();
// 私有构造器
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return INSTANCE;
}
}//此模式线程安全,但是可能造成资源浪费
public class UnsafeLazySingleton {//懒汉式(基础版本)
private static UnsafeLazySingleton instance;
private UnsafeLazySingleton() {}
public static UnsafeLazySingleton getInstance() {
if (instance == null) {
instance = new UnsafeLazySingleton();
}
return instance;
}
}//此模式线程不安全
public class SynchronizedLazySingleton {//懒汉式(采用同步方式)
private static SynchronizedLazySingleton instance;
private SynchronizedLazySingleton() {}
public static synchronized SynchronizedLazySingleton getInstance() {
if (instance == null) {
instance = new SynchronizedLazySingleton();
}
return instance;
}
}//此模式线程安全但是效率较低
抽象工厂模式是最常用的创建型设计模式,它提供了一种创建相关或依赖对象族的接口,而无需指定它们的具体类。其主要有4大部分:
抽象工厂:声明创建产品族中各个产品的方法
具体工厂:实现抽象工厂接口,创建具体产品
抽象产品:声明产品接口
具体产品:实现抽象产品接口的具体类
其主要关注的是可以生产的产品族(如a族,b族,c族等),可以轻松的添加和切换生产的产品族,
// 产品A接口
interface ProductA {
void use();
}
// 产品B接口
interface ProductB {
void operate();
}
//具体实现
// 产品A的型号1
class ProductA1 implements ProductA {
@Override
public void use() {
System.out.println("使用A1型产品");
}
}
// 产品A的型号2
class ProductA2 implements ProductA {
@Override
public void use() {
System.out.println("使用A2型产品");
}
}
// 产品B的型号1
class ProductB1 implements ProductB {
@Override
public void operate() {
System.out.println("操作B1型产品");
}
}
// 产品B的型号2
class ProductB2 implements ProductB {
@Override
public void operate() {
System.out.println("操作B2型产品");
}
}
//定义抽象工厂接口
interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
//实现具体工厂
// 生产第一套产品(A1+B1)
class Factory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ProductA1();
}
@Override
public ProductB createProductB() {
return new ProductB1();
}
}
// 生产第二套产品(A2+B2)
class Factory2 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ProductA2();
}
@Override
public ProductB createProductB() {
return new ProductB2();
}
}
//客户端使用
public class Client {
public static void main(String[] args) {
// 使用第一套工厂生产产品
AbstractFactory factory1 = new Factory1();
ProductA a1 = factory1.createProductA();
ProductB b1 = factory1.createProductB();
a1.use(); // 输出: 使用A1型产品
b1.operate(); // 输出: 操作B1型产品
System.out.println("------");
// 使用第二套工厂生产产品
AbstractFactory factory2 = new Factory2();
ProductA a2 = factory2.createProductA();
ProductB b2 = factory2.createProductB();
a2.use(); // 输出: 使用A2型产品
b2.operate(); // 输出: 操作B2型产品
}
}
适配器模式是一种结构型设计模式,它允许不兼容的接口能够一起工作。适配器模式就像现实世界中的电源适配器,让不同规格的插头能够插入插座。其通过包装对象的方式,将一个类的接口转换成客户端期望的另一个接口,从而使原本因接口不兼容而无法一起工作的类可以协同工作。
适配器模式主要有三种角色:
目标接口:客户端期望的接口
适配者:需要被适配的现有类
适配器:包装适配者并实现目标接口
其实现代码如下:
//类适配器(通过继承实现)
// 目标接口
interface Target {
void request();
}
// 需要适配的类
class Adaptee {
public void specificRequest() {
System.out.println("Adaptee的特殊请求");
}
}
// 类适配器(继承Adaptee并实现Target)
class ClassAdapter extends Adaptee implements Target {
@Override
public void request() {
specificRequest(); // 调用父类方法
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Target target = new ClassAdapter();
target.request(); // 输出: Adaptee的特殊请求
}
}
//对象适配器(通过组合实现)
// 目标接口
interface Target {
void request();
}
// 需要适配的类
class Adaptee {
public void specificRequest() {
System.out.println("Adaptee的特殊请求");
}
}
// 对象适配器(组合Adaptee并实现Target)
class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest();
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request(); // 输出: Adaptee的特殊请求
}
}
其优点众多,包括复用性强,可以实现多个不兼容的类一起工作,使用灵活且方便,同时还能降低程序的耦合度,遵循开闭原则,通过引入新的适配器进行适配而不是修改源代码。但是如果其会带来一些额外的开销,同时由于增加了新的类和对象,会提高程序的复杂度。
最后是代理模式,其是一种结构型设计模式,为其他对象提供一种代理以控制对这个对象的访问。代理模式就像现实生活中的"中介",在客户端和目标对象之间起到中介作用。其主要是通过创建一个代理对象来控制对原始对象的访问,可以在不改变原始类代码的情况下,增加额外的功能或控制访问。主要实现4大功能:
访问控制:控制对原始对象的访问权限
功能增强:在不修改原始对象的情况下添加额外功能
延迟初始化:推迟高开销对象的创建
远程访问:为远程对象提供本地代表
其主要包含3大角色,分别是:
抽象主题:定义真实主题和代理主题的共同接口
真实主题:实际执行业务逻辑的对象
代理:持有真实主题的引用,控制对真实主题的访问
其有多种实现方式,具体代码如下:
//1.静态代理
/**
*手动编写代理类
*一个真实主题对应一个代理类
*编译时确定代理关系
*/
// 抽象主题
interface Image {
void display();
}
// 真实主题
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("加载图片: " + filename);
}
@Override
public void display() {
System.out.println("显示图片: " + filename);
}
}
// 代理
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); // 延迟初始化
}
preDisplay();
realImage.display();
postDisplay();
}
private void preDisplay() {
System.out.println("显示前准备工作");
}
private void postDisplay() {
System.out.println("显示后清理工作");
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Image image = new ProxyImage("test.jpg");
// 图片直到真正需要显示时才会加载
image.display();
}
}
//2.jdk动态代理
/**
*运行时动态生成代理类
*只能代理接口
*通过InvocationHandler统一处理所有方法调用
*/
import java.lang.reflect.*;
// 抽象主题
interface UserService {
void addUser(String name);
void deleteUser(String name);
}
// 真实主题
class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("添加用户: " + name);
}
@Override
public void deleteUser(String name) {
System.out.println("删除用户: " + name);
}
}
// 调用处理器
class UserServiceInvocationHandler implements InvocationHandler {
private Object target;
public UserServiceInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("--- 开始执行 " + method.getName() + " ---");
Object result = method.invoke(target, args);
System.out.println("--- 结束执行 " + method.getName() + " ---");
return result;
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new UserServiceInvocationHandler(realService)
);
proxy.addUser("张三");
proxy.deleteUser("李四");
}
}
//3.CGLIB动态代理
/**
*通过继承方式实现代理
*可以代理普通类(不需要接口)
*性能通常比JDK动态代理好
*不能代理final类和方法
*/
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
// 真实主题(不需要实现接口)
class ProductService {
public void addProduct(String name) {
System.out.println("添加产品: " + name);
}
public void deleteProduct(String name) {
System.out.println("删除产品: " + name);
}
}
// 方法拦截器
class ProductServiceInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println(">>> 调用前: " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("<<< 调用后: " + method.getName());
return result;
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ProductService.class);
enhancer.setCallback(new ProductServiceInterceptor());
ProductService proxy = (ProductService) enhancer.create();
proxy.addProduct("手机");
proxy.deleteProduct("电脑");
}
}