Java高级开发必备-设计模式
观察者模式
定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。
服务接口,所有服务实现此接口
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
所有观察者需要实现此接口
public interface Observer {
void update(String msg);
}
服务的实现类
public class SubjectForOne implements Subject {
private ArrayList<Observer> observers = new ArrayList<>();
private String msg;
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
int index = observers.indexOf(observer);
if (index >= 0) {
observers.remove(index);
}
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(msg);
}
}
/**
* 主题更新信息
*
* @param msg
*/
public void setMsg(String msg) {
this.msg = msg;
notifyObservers();
}
}
模拟第一个使用者
public class ObserverUser1 implements Observer {
public ObserverUser1(Subject subject) {
subject.registerObserver(this);
}
@Override
public void update(String msg) {
System.out.println("-----ObserverUser1: " + msg + "");
}
}
测试
public class Test {
public static void main(String[] args) {
// 创建服务号
SubjectForOne subject = new SubjectForOne();
// 创建两个订阅者
ObserverUser1 user1 = new ObserverUser1(subject);
ObserverUser2 user2 = new ObserverUser2(subject);
subject.setMsg("3D号为:127");
subject.setMsg("3D号为:000");
}
}
工厂模式
-
静态工厂模式
项目中的辅助类,TextUtil.isEmpty等,类+静态方法。 -
简单工厂模式
通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。 -
工厂方法模式
定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法模式把类实例化的过程推迟到子类。 -
抽象工厂模式
提供一个接口,用于创建相关的或依赖对象的家族,而不需要明确指定具体类。
接口工厂
public interface Factory {
Worker work();
Machine start();
}
各工厂实现工厂接口
public class AFactory implements Factory {
@Override
public Worker work() {
return new AWorker();
}
@Override
public Machine start() {
return new AMachine();
}
}
public class Worker {
public String msg = "I am worker.";
}
public class AWorker extends Worker {
public AWorker() {
this.msg = "I am worker A.";
}
}
public class Main {
public void start(Factory factory) {
Worker worker = factory.work();
//Machine machine = factory.start();
System.out.println("worker: " + worker.msg + ", machine: " + machine.msg);
}
public void pack() {
System.out.println("packing");
}
}
单例设计模式
单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例。
-
饿汉
public class SingletonEHan { private SingletonEHan() {} private static SingletonEHan singletonEHan = new SingletonEHan(); public static SingletonEHan getInstance() { return singletonEHan; } }
-
懒汉-双重校验锁
public class SingletonLanhan { private SingletonLanhan() { } private static SingletonLanhan instance; private static SingletonLanhan getInstance() { if (instance == null) { synchronized (SingletonLanhan.class) { if (instance == null) { instance = new SingletonLanhan(); } } } return instance; } }
-
内部类
public class SingletonIn { private SingletonIn() { } private static class SingletonInHodler { private static SingletonIn singletonIn = new SingletonIn(); } public static SingletonIn getSingletonIn() { return SingletonInHodler.singletonIn; } }
-
枚举
public enum SingletonEnum { instance; private SingletonEnum() { } public void method() { System.out.println("method"); } } // SingletonEnum.instance.method(); public enum SingtonEnum { USERS; private Users users; private SingtonEnum() { users = new Users(1); } public Users get() { return users; } } // SingtonEnum.USERS.get()
适配器模式
将一个类的接口转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以相互合作。这个定义还好,说适配器的功能就是把一个接口转成另一个接口。
提供5V电压的接口
public interface V5Power {
int v5();
}
一部手机
public class Mobile {
public void inputPower(V5Power power) {
int p = power.v5();
System.out.println("我需要的是5V电压充电,现在是" + p + "V");
}
}
200V电
public class V20Power {
public int v200() {
System.out.println("我提供200V电源");
return 200;
}
}
适配器,完成200V转5V
public class V5PowerAdapter implements V5Power {
private int v200;
public V5PowerAdapter(V20Power power) {
this.v200 = power.v200();
}
@Override
public int v5() {
System.out.println("适配器: 经过复杂的操作,将" + v200 + "v电压转为5v");
return 5;
}
}
public class Test {
public static void main(String[] args) {
Mobile mobile = new Mobile();
V5Power v5 = new V5PowerAdapter(new V20Power());
mobile.inputPower(v5);
}
}
装饰者模式
若要扩展功能,装饰者提供了比集成更有弹性的替代方案,动态地将责任附加到对象上。
装备的超类
public interface IEquip {
int calcu();
String descr();
}
各个装备的实现类,如武器
public class ArmEquip implements IEquip {
@Override
public int calcu() {
return 5;
}
@Override
public String descr() {
return "屠龙宝刀";
}
}
装饰品的超类
public interface IEquipDecorator extends IEquip {
}
装饰品的实现类
public class BlueGemDecotator implements IEquipDecorator {
private IEquip equip;
public BlueGemDecotator(IEquip equip) {
this.equip = equip;
}
@Override
public int calcu() {
return 10 + equip.calcu();
}
@Override
public String descr() {
return equip.descr() + " 点击就送";
}
}
public class Test {
public static void main(String[] args) {
IEquip equip = new BlueGemDecotator(new ArmEquip());
//IEquip equip = new BlueGemDecotator(new BlueGemDecotator(new ArmEquip()));
System.out.println("攻击力:" + equip.calcu());
System.out.println("装备描述:" + equip.descr());
}
}
命令模式
将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。(简化: 将请求封装成对象,将动作请求者和动作执行者解耦。)
家电API
public class Door {
public void open() {
System.out.println("打开门……");
}
public void close() {
System.out.println("关闭门……");
}
}
统一的命令接口
public interface Command {
void execute();
}
家电实现该接口
public class DoorOpenCommand implements Command {
private Door door;
public DoorOpenCommand(Door door) {
this.door = door;
}
@Override
public void execute() {
door.open();
}
}
遥控器
public class Control {
private static final int CONTROL_SIZE = 9;
// 遥控器按钮 一共9个按钮
private Command[] commands;
public Control() {
commands = new Command[CONTROL_SIZE];
for (int i = 0; i < CONTROL_SIZE; i++) {
commands[i] = new NoCommand();
}
}
/**
* 设置每个按钮对应的位置
*/
public void setCommands(int index, Command command) {
commands[index] = command;
}
/**
* 模拟点击按钮
*/
public void press(int index) {
commands[index].execute();
}
}
定义一个命令,可以运行一系列操作
public class QuickCommand implements Command {
private Command[] commands;
public QuickCommand(Command[] commands) {
this.commands = commands;
}
@Override
public void execute() {
for (Command command : commands) {
command.execute();
}
}
}
测试
public class Test {
public static void main(String[] args) {
Control control = new Control();
Door door = new Door();
// 执行单个命令
control.setCommands(1, new DoorOpenCommand(door));
control.press(1);
// 执行批量命令
QuickCommand mutils = new QuickCommand(new Command[]{new DoorOpenCommand(door), new DoorCloseCommand(door)});
control.setCommands(3, mutils);
control.press(3);
control.press(5);
}
}
策略模式
现实生活中,我们要做一件事情或者完成某项工作,往往有很多种途径。比如我们现在线下的支付方式有了很多种选择,只要我们手机在身上,就可以用微信或支付宝。
在软件设计层面,我们把各种支付方式叫做策略。如果不考虑设计模式的话,我们可能会在一个类中用if…else方式来选择支付方式,但如果以后要改变支付方式,比如不能用微信支付了,或者新增了其他支付方式,我们就要改变这个类,这会带来代码维护的麻烦。
算法体现了几个设计原则,第一、把变化的代码从不变的代码中分离出来;第二、针对接口编程而不是具体类(定义了策略接口);第三、多用组合,少用继承(客户通过组合方式使用策略)。
从王者荣耀看设计模式
定义召唤师技能接口
public interface ISkill {
/**
* 使用召唤师技能
*/
abstract void useSkill();
}
实现各个技能,如“疾跑”,后者“闪现”
public class JiPao implements ISkill {
@Override
public void useSkill() {
System.out.println("疾跑,增加30%移动速度");
}
}
定义英雄,抽象类(抽取公共)
public abstract class Hero {
// 英雄名称
private String heroName;
// 召唤师技能
private ISkill iSkill;
// 英雄自我介绍
public abstract void display();
// 英雄普通攻击
public abstract void normalAttack();
public void skill() {
iSkill.useSkill();
}
// get/set
}
实现具体的英雄,如“后羿”
public class HouYi extends Hero {
public HouYi() {
super.setHeroName("后羿");
}
@Override
public void display() {
System.out.println("我是后羿,最强射手");
}
@Override
public void normalAttack() {
System.out.println("xiuxiuxiu");
}
}
下面是测试
public static void main(String[] args) {
// 选择英雄
Hero hero = new HouYi();
// 英雄自我介绍
hero.display();
// 选择召唤师技能
hero.setiSkill(new JiPao()); // 面向接口编程
// 游戏开始
// 普通攻击
hero.normalAttack();
// 使用技能
hero.skill();
}
除该场景外,我们还可以应用于支付通道,用于多个支付通道的路由选择,及减少后期由于通道增减带来的代码维护难度
责任链模式
在这种模式中,通常每个接收者都包含对另一个接收者的引用。
public abstract class AbstractLogger {
public static int INFO = 1;
public static int DEBUG = 2;
public static int ERROR = 3;
protected int level;
protected AbstractLogger nextLogger;
public void setNextLogger(AbstractLogger nextLogger) {
this.nextLogger = nextLogger;
}
public void log(int level, String message) {
if (this.level <= level) {
write(message);
}
if (nextLogger != null) {
nextLogger.log(level, message);
}
}
abstract protected void write(String message);
}
多个Logger
public class ConsoleLogger extends AbstractLogger {
public ConsoleLogger(int level) {
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("ConsoleLogger=" + message + ", level=" + this.level);
}
}
测试类
public class Test {
private static AbstractLogger getChainLoggers() {
ConsoleLogger consoleLogger = new ConsoleLogger(AbstractLogger.DEBUG);
ErrorLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
FileLogger fileLogger = new FileLogger(AbstractLogger.INFO);
consoleLogger.setNextLogger(errorLogger);
errorLogger.setNextLogger(fileLogger);
return consoleLogger;
}
public static void main(String[] args) {
AbstractLogger abstractLogger = getChainLoggers();
abstractLogger.log(AbstractLogger.DEBUG, "Hello World");
}
}