设计模式
结构性模式
主要关注类和对象的组合模式
外观模式
提供一个接口,用来访问子系统中的一群接口
定义了一个高层接口,让子系统使用更加容易
假设有一个电脑的启动流程,设计CPU、内存、硬盘等多个子系统,每个子系统都有自己的复杂操作
// 1. CPU子系统
class CPU {
public void start() {
System.out.println("CPU启动...");
}
}
// 2. 内存子系统
class Memory {
public void load() {
System.out.println("内存加载数据...");
}
}
// 3. 硬盘子系统
class HardDrive {
public void read() {
System.out.println("硬盘读取数据...");
}
}如果我们直接创建对应的对象,再依次调用其中方法就会使代码很复杂
public class Main {
public static void main(String[] args) {
CPU cpu = new CPU();
Memory memory = new Memory();
HardDrive hardDrive = new HardDrive();
// 电脑启动流程
cpu.start();
memory.load();
hardDrive.read();
}
}这个时候我们引入外观模式,对于这些子系统进行封装,提供总的启动方法,即可简化
// 外观类(封装所有底层操作)
class ComputerFacade {
private CPU cpu;
private Memory memory;
private HardDrive hardDrive;
public ComputerFacade() {
this.cpu = new CPU();
this.memory = new Memory();
this.hardDrive = new HardDrive();
}
// 提供一个简化的启动方法
public void startComputer() {
cpu.start();
memory.load();
hardDrive.read();
System.out.println("电脑启动完毕!");
}
}在客户端使用的时候就只需要调用一个方法即可调用
public class Client {
public static void main(String[] args) {
ComputerFacade computer = new ComputerFacade();
computer.startComputer(); // 一键启动电脑!
}
}子系统修改不影响客户端代码,便于维护,所有复杂操作集中在一个入口
适配器模式
是作为两个不兼容接口之间的桥梁,将一个类的接口转化为另一个接口(客户所希望的),使得将原先由于不兼容的接口导致的不能一起工作的类变得可以一起工作,结合了两个独立的接口功能
使用角色:被适配者、目标接口、适配器
来个真实场景:你是一个Java码农,你只会码Java,现在你需要参与到Golang工厂的开发中,你需要去实现Golang的接口方法
但是你不想要去学Golang,你只想复用一下Java的代码,这个时候你就需要使用到AiAdapter转化工具,这就是一个适配器,由它来实现Golang的接口,你只需要作为它的子类,由他调用你的代码作为转化即可
目标接口
public interface Golang {
void work();
}被适配者
public class JavaProgrammer {
public void code() {
System.out.println("码农码Java");
}
}适配器
public class AiAdapter implements Golang {
private JavaProgrammer programmer;
public AiAdapter(JavaProgrammer programmer) {
this.programmer = programmer;
}
@Override
public void work() {
programmer.code();
System.out.println("AI将Java语言转化为Go语言");
System.out.println("运行代码");
}
}在使用的时候,直接调用适配器的实现方法即可
public static void main(String[] args) {
JavaProgrammer javaProgrammer = new JavaProgrammer();
Golang golangProj = new AiAdapter(javaProgrammer);
golangProj.work();
}桥接模式
用于把抽象化和实现化进行解耦,使得两者可以独立变化(组合优于继承)
分离抽象和实现,避免继承膨胀
现在有这么一个场景
// 支付方式
class AliPayWithSMS {
public void pay() {
System.out.println("支付宝支付");
}
public void notifyBySMS() {
System.out.println("短信提醒");
}
}
class AliPayWithEmail {
public void pay() {
System.out.println("支付宝支付");
}
public void notifyByEmail() {
System.out.println("邮件提醒");
}
}
class WeChatPayWithSMS {
public void pay() {
System.out.println("微信支付");
}
public void notifyBySMS() {
System.out.println("短信提醒");
}
}
class WeChatPayWithEmail {
public void pay() {
System.out.println("微信支付");
}
public void notifyByEmail() {
System.out.println("邮件提醒");
}
}每一个实现都需要匹配对应的支付方式,消息类型,如果5种支付方式,3种邮件,就需要实现15个实现类,我们用桥接模式对他进行改造
设计消息接口,实现几种通知的实现
// 提醒方式接口
interface NotifyMethod {
void notifyUser();
}
// 具体实现:短信提醒
class SMSNotify implements NotifyMethod {
@Override
public void notifyUser() {
System.out.println("短信提醒");
}
}
// 具体实现:邮件提醒
class EmailNotify implements NotifyMethod {
@Override
public void notifyUser() {
System.out.println("邮件提醒");
}
}设计支付的抽象类
// 支付抽象类(持有提醒方式)
abstract class Payment {
protected NotifyMethod notifyMethod; // 组合提醒方式
public Payment(NotifyMethod notifyMethod) {
this.notifyMethod = notifyMethod;
}
abstract void pay();
}定义具体的支付方法
// 支付宝支付
class AliPay extends Payment {
public AliPay(NotifyMethod notifyMethod) {
super(notifyMethod);
}
@Override
void pay() {
System.out.print("支付宝支付,");
notifyMethod.notifyUser();
}
}
// 微信支付
class WeChatPay extends Payment {
public WeChatPay(NotifyMethod notifyMethod) {
super(notifyMethod);
}
@Override
void pay() {
System.out.print("微信支付,");
notifyMethod.notifyUser();
}
}这样我们就只需要实现支付的几个实现,更具需要传入通知的类型即可
public class Client {
public static void main(String[] args) {
// 支付宝 + 短信
Payment aliPaySMS = new AliPay(new SMSNotify());
aliPaySMS.pay();
// 微信 + 邮件
Payment weChatPayEmail = new WeChatPay(new EmailNotify());
weChatPayEmail.pay();
// 如果新增“推送通知”,只需扩展 NotifyMethod,无需改支付类!
}
}组合模式
又称为部分整体模式,适用于把一组相似的对象当作一个单一对象
根据树形结构来组合对象,用来表示部分以及整体层次
@Data
public class Employee {
private String name;
private String dept;
private Long salary;
private List<Employee> employeeList;
public Employee(String name, String dept, Long salary) {
this.name = name;
this.dept = dept;
this.salary = salary;
this.employeeList = new ArrayList<Employee>();
}
public void addEmployee(Employee employee) {
employeeList.add(employee);
}
public void removeEmployee(Employee employee) {
employeeList.remove(employee);
}
}创建完成对象后通过方法添加关联的人员
public class Main {
public static void main(String[] args) {
Employee ceo = new Employee("张三", "1", 200L);
Employee management = new Employee("李四", "2", 150L);
Employee seller = new Employee("王五", "3", 100L);
Employee store = new Employee("赵六", "4", 50L);
ceo.addEmployee(management);
management.addEmployee(seller);
management.addEmployee(store);
System.out.println(ceo);
for (Employee manage : ceo.getEmployeeList()) {
System.out.println(manage);
for (Employee emp : manage.getEmployeeList()) {
System.out.println(emp);
}
}
}
}Employee(name=张三, dept=1, salary=200, employeeList=[Employee(name=李四, dept=2, salary=150, employeeList=[Employee(name=王五, dept=3, salary=100, employeeList=[]), Employee(name=赵六, dept=4, salary=50, employeeList=[])])])
Employee(name=李四, dept=2, salary=150, employeeList=[Employee(name=王五, dept=3, salary=100, employeeList=[]), Employee(name=赵六, dept=4, salary=50, employeeList=[])])
Employee(name=王五, dept=3, salary=100, employeeList=[])
Employee(name=赵六, dept=4, salary=50, employeeList=[])代理模式
可以将代理对象和目标对象相分离,降低耦合度,拥有更好的扩展性
是AOP面向切面编程中的核心
静态代理
有一个接口以及接口方法的实现类
public interface OrderService {
void generate();
void modify();
void detail();
}public class OrderServiceImpl implements OrderService {
@Override
public void generate() {
System.out.println("订单生成");
}
@Override
public void modify() {
System.out.println("订单修改");
}
@Override
public void detail() {
System.out.println("订单详情");
}
}我们现在需要增添功能:对每个业务接口中业务方法的解决耗时,可以在每个业务的前后取时间相减,但是违背了OCP原则,且没有复用代码
我们使用代理模式处理,写一个OrderService的代理对象
public class OrderServiceProxy implements OrderService{
//写入公共接口,耦合度低
private OrderService orderService;
public OrderServiceProxy(OrderService orderService) {
this.orderService = orderService;
}
@Override
public void generate() {
long begin = System.currentTimeMillis();
orderService.generate();
long end = System.currentTimeMillis();
System.out.println("Generate Order Time: " + (end - begin));
}
@Override
public void modify() {
long begin = System.currentTimeMillis();
orderService.modify();
long end = System.currentTimeMillis();
System.out.println("Modify Order Time: " + (end - begin));
}
@Override
public void detail() {
long begin = System.currentTimeMillis();
orderService.detail();
long end = System.currentTimeMillis();
System.out.println("Detail Order Time: " + (end - begin));
}
}在主函数中调用代理对象的方法即可完成功能的增强
public class Main {
public static void main(String[] args) {
OrderService orderService = new OrderServiceImpl();
OrderService proxy = new OrderServiceProxy(orderService);
proxy.generate();
proxy.modify();
proxy.detail();
}
}订单生成
Generate Order Time: 0
订单修改
Modify Order Time: 0
订单详情
Detail Order Time: 0虽然解决了OCP的开闭问题,但是每个接口需要实现一个代理类,会导致类的数量急剧增多,我们在实际会使用到动态代理
动态代理
JDK动态代理技术:只能代理接口
CGLIB:开源项目,高性能Code生成类库,底层通过继承的方式实现,可以代理类
public interface OrderService {
void generate();
void modify();
void detail();
}实现类
public class OrderServiceImpl implements OrderService {
@Override
public void generate() {
System.out.println("订单生成");
}
@Override
public void modify() {
System.out.println("订单修改");
}
@Override
public void detail() {
System.out.println("订单详情");
}
}动态代理处理器
public class TimerInvocationHandler implements InvocationHandler {
private Object target;
public TimerInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long begin = System.currentTimeMillis();
Object object = method.invoke(target, args);
long end = System.currentTimeMillis();
System.out.println("Time: " + (end - begin));
return object;//返回方法调用的返回值
}
}使用
public class ProxyTest {
public static void main(String[] args) {
//创建目标对象
OrderService target = new OrderServiceImpl();
//创建代理类,借助jdk中的类
//1.类加载器 2.代理类实现的接口 3.调用处理器
Object proxyObj = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
//为了创建代理类,需要获取目标类的类加载器
target.getClass().getInterfaces(),
//为了实现接口方法,需要获取类的所有接口对象
new TimerInvocationHandler(target)
//传入实现了处理接口的实例对象
);
OrderService proxy = (OrderService) proxyObj;
//调用代理类
proxy.generate();
proxy.modify();
proxy.detail();
}
}装饰模式
在原有对象不改变的基础上,将对象的功能添加
扩展一个类的功能或给一个类添加附加职责
被装饰的抽象类
abstract class ABatterCake {
protected abstract String getDesc();
protected abstract int cost();
}被装饰的实现类
public class BatterCake extends ABatterCake{
@Override
protected String getDesc() {
return "煎饼";
}
@Override
protected int cost() {
return 6;
}
}拓展的装饰抽象类:加了个another方法,可以让实现类继承实现
package com;
abstract class ADecorator extends ABatterCake{
private ABatterCake batterCake;
public ADecorator(ABatterCake batterCake) {
this.batterCake = batterCake;
}
@Override
protected String getDesc() {
return this.batterCake.getDesc();
}
@Override
protected int cost() {
return this.batterCake.cost();
}
protected abstract void another();
}实现具体装饰类
public class EggBatterCake extends ADecorator{
public EggBatterCake(ABatterCake batterCake) {
super(batterCake);
}
@Override
protected void another() {
System.out.println("加蛋");
}
}使用
public class Main {
public static void main(String[] args) {
ADecorator eggCake = new EggBatterCake(new BatterCake());
System.out.println(eggCake.getDesc());
System.out.println(eggCake.cost());
eggCake.another();
}
}享元模式
提供了减少对象数量,从而改善应用所需的对象结构方式
员工接口
public interface Employee {
void report();
}经理实现
@Data
public class Manager implements Employee{
private String department;
private String noteContent;
public Manager(String department) {
this.department = department;
}
@Override
public void report() {
System.out.println(department + " " + noteContent);
}
}通过ManagementFactory获取对应的经理,减少资源开销,创建过的经理会被放入EMPLOYEE_MAP中,避免了重复放入
public class ManagementFactory {
private static final Map<String, Employee> EMPLOYEE_MAP = new HashMap<String, Employee>();
public static Employee getEmployee(String department) {
Manager manager = (Manager) EMPLOYEE_MAP.get(department);
if (manager == null) {
manager = new Manager(department);
System.out.println("创建部门经理" + department);
manager.setNoteContent("经济相关的内容");
EMPLOYEE_MAP.put(department, manager);
}
return manager;
}
}使用
public class Main {
public static void main(String[] args) {
Employee manager = ManagementFactory.getEmployee("金融部门");
manager.report();
}
}