Java设计模式
六大原则
- 单一职责原则
- 开闭原则: 开放扩展, 关闭修改(相同功能的if-else, 封装成接口)
- 里氏替换原则
- 依赖倒置: 抽象/接口不依赖实现类
- 接口隔离: 最小化接口
- 迪米特原则: 只和最直接的类通信
1. 创建型
1.1 单例模式
单例模式保证每次获取一个类的实例时,都是同一个实例,防止重复性的创建一些资源。单例模式的实现方式有很多,主要的区别体现在是否支持懒加载、是否线程安全等方面。
// 迫不及待的准备好"食物", 所以叫饿汉
public class Singleton {
public static final Singleton s = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return s;
}
}
// 用的时候才初始化, 所以叫懒汉
public class Singleton {
public static Singleton s = null;
private Singleton(){}
private static Singleton getInstance(){
if(s == null){
s = new Singleton();
}
return s;
}
// 线程安全版本
private static synchronized Singleton getInstanceSafe(){
if(s == null){
s = new Singleton();
}
return s;
}
}
public class Singleton {
public volatile static Singleton s = null;
private Singleton(){}
public static Singleton getInstace(){
if(s == null){
synchronized (Singleton.class) {
if(s == null) {
s = new Singleton();
}
}
}
return s;
}
}
public class Singleton {
private Singleton(){}
private static final class SHolder {
public static final Singleton s = new Singleton();
}
private static Singleton getInstance(){
return SHolder.s;
}
}
public enum Singleton {
INSTANCE;
public void func(){}
}
注意
需要注意反序列化、线程安全、clone、反射可以破坏单例
1.2 建造者
建造者模式将复杂的构建过程和内部表示分离,适用于不同执行顺序的结果不同,或参数较多且存在默认值的场景。
package computer;
public class Computer {
private Host host;
private KeyBoard keyBoard;
private Mouse mouse;
private Screen screen;
public static Builder Builder(){
return new Builder();
}
private Computer(Computer.Builder builder){
// 根据参数构建Computer
this.host = new Host();
this.keyBoard = new KeyBoard();
this.mouse = new Mouse();
this.screen = new Screen();
}
public static class Builder {
// 默认策略
private String host = "HP";
private String keyBoard = "Rainy75";
private String mouse = "Logic";
private String screen = "Dell";
private Builder(){}
public Builder Host(String host){
this.host = host;
return this;
}
public Builder KeyBoard(String keyBoard){
this.keyBoard = keyBoard;
return this;
}
public Builder Mouse(String mouse){
this.mouse = mouse;
return this;
}
public Builder Screen(String screen){
this.screen = screen;
return this;
}
public Computer build(){
return new Computer(this);
}
}
}
// 使用方法
Computer computer = Computer.Builder().Host("apple").build();
1.3 原型模式
原型模式用来解决创建重复对象时,初始化的资源消耗大、过程复杂的问题。
注意
- 简单的类通过Cloneable反而速度不如重新new一个
- 直接clone不行么?
public class Document{
private ArrayList<String> mImages = new ArrayList<>();
public Document() {}
@Override
protected Document clone() throws CloneNotSupportedException {
try{
Document document = (Document) super.clone();
// 浅拷贝
document.mImages = this.mImages;
// 深拷贝
document.mImages = (ArrayList<String>) this.mImages.clone();
return document;
}catch (CloneNotSupportedException e){
}
return null;
}
}
1.4 工厂模式
工厂模式的介绍上,网上的很多文章说法都不太一样,这里根据自己的理解记录一下
1.4.1 简单工厂模式
简单工厂模式通过一个统一工厂,创建一系列继承自同一父类的产品。然而简单工厂模式不符合开闭原则,当新增一个产品时,仍需要修改case
部分进行判断。
// Hp、Huawei、Xiaomi 都 extends Computer
public class EasyFactory {
public static Computer product(String type){
return switch (type) {
case "Hp" -> new HpComputer();
case "Huawei" -> new HuaweiComputer();
case "Xiaomi" -> new XiaomiComputer();
default -> null;
};
}
}
1.4.2 工厂模式
工厂模式定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
public interface ComputerFactory {
Computer product();
}
public class HpFactory implements ComputerFactory {
@Override
public Computer product() {
return new HpComputer();
}
}
1.4.3 抽象工厂模式
抽象工厂模式是将多个相互关联的产品组合到一个抽象的工厂中,确保一个工厂生产的产品都是相互关联的。我理解为相比工厂模式从生产单一产品,变成了生产多个产品。
public interface AbstractFactory {
Computer productComputer();
Phone productPhone();
}
public class HpFactory implements AbstractFactory{
@Override
public Computer productComputer() {
return new HpComputer();
}
@Override
public Phone productPhone() {
return new HpPhone();
}
}
2. 行为型
2.1 策略模式
策略模式可以将原本用if-else
来选择代码逻辑的场景进行包装,并提供统一上下文给外部调用。
比如程序中可能会调用原生、QQ、微信的电话,例子如下:
public class CallContext {
private final Call call;
public CallContext(Call call) {
this.call = call;
}
public void makeCall() {
call.makeCall();
}
}
public interface Call {
void makeCall();
}
public class NativeCall implements Call {
@Override
public void makeCall() {
System.out.println("native");
}
}
public class QQCall implements Call {
@Override
public void makeCall() {
System.out.println("qq");
}
}
public class WechatCall implements Call {
@Override
public void makeCall() {
System.out.println("wechat");
}
}
2.2 状态模式
状态模式和策略模式类似,但状态模式更强调一个类在不同状态下具有不同的行为。所以在具体实现上,策略模式是直接将内部的实现细节暴露在construct
上,而状态模式则是对外暴露setState
方法,允许动态的改变状态。
比如一个手机在开机、关机两个状态下对拨打电话和发送短信的反馈会不同:
public class PhoneContext{
private PhoneState state;
public void setState(PhoneState state){
this.state = state;
}
public void makeCall() {
state.makeCall();
}
public void sendMsg() {
state.sendMsg();
}
public void close(){
state.close();
state = new PhoneCloseState();
}
public void open(){
state.open();
state = new PhoneOpenState();
}
}
public interface PhoneState {
void makeCall();
void sendMsg();
void close();
void open();
}
public class PhoneCloseState implements PhoneState {
@Override
public void makeCall() {
System.out.println("通话失败,手机关机中");
}
@Override
public void sendMsg() {
System.out.println("短信失败,手机关机中");
}
@Override
public void close() {
System.out.println("关机失败,当前正处于关机状态");
}
@Override
public void open() {
System.out.println("开机成功");
}
}
public class PhoneOpenState implements PhoneState {
@Override
public void makeCall() {
System.out.println("通话成功");
}
@Override
public void sendMsg() {
System.out.println("短信成功");
}
@Override
public void close() {
System.out.println("关机成功");
}
@Override
public void open() {
System.out.println("开机失败,当前正处于开机状态");
}
}
2.3 责任链模式
责任链模式解决了一组程序的先后执行关系,处于链条上的程序均有机会执行代码,同时也可以阻断后续代码的执行。
考虑一个三级审批流程如下:
public abstract class ExamineHandler {
private ExamineHandler next;
public ExamineHandler next() {
return next;
}
public ExamineHandler appendNext(ExamineHandler next) {
this.next = next;
return this;
}
public abstract void handle(String input);
}
public class L1Examine extends ExamineHandler {
@Override
public void handle(String input) {
System.out.println("L1匹配");
if(input.equals("L1")){
return;
}
super.next().handle(input);
}
}
public class L2Examine extends ExamineHandler {
@Override
public void handle(String input) {
System.out.println("L2匹配");
if(input.equals("L2")){
return;
}
super.next().handle(input);
}
}
public class L3Examine extends ExamineHandler {
@Override
public void handle(String input) {
System.out.println("L3匹配");
if(input.equals("L3")){
return;
}
super.next().handle(input);
}
}
2.4 观察者模式
观察者模式实现了订阅-发布系统,当一个对象改变时,其他所有依赖他的对象都会得到通知。
对于一个订阅具有两个观察者的代码如下:
public class Subject {
private List<Observer> observers;
public Subject() {
this.observers = new ArrayList<>();
}
public void addObserver(Observer observer){
observers.add(observer);
}
public void notifySubjects(){
observers.forEach(Observer::update);
}
}
public interface Observer {
void update();
}
public class ObserverA implements Observer{
@Override
public void update() {
System.out.println("A");
}
}
public class ObserverB implements Observer{
@Override
public void update() {
System.out.println("B");
}
}
2.5 模版方法模式
模版方法模式定义了程序的架构,并将具体的步骤延迟到子类中实现。
代码如下:
public abstract class Template {
public void execute(){
stepOne();
stepTwo();
stepThree();
}
protected abstract void stepOne();
protected abstract void stepTwo();
protected abstract void stepThree();
}
public class TemplateImpl extends Template{
@Override
protected void stepOne() {
System.out.println("1");
}
@Override
protected void stepTwo() {
System.out.println("2");
}
@Override
protected void stepThree() {
System.out.println("3");
}
}
3. 结构型
3.1 代理模式
代理模式通过对其他对象提供代理来控制对这个对象的访问。
public class PhoneProxy implements Phone{
private Phone phone;
public PhoneProxy(Phone phone) {
this.phone = phone;
}
@Override
public void makeCall() {
System.out.println("ready to call");
phone.makeCall();
System.out.println("call finish");
}
}
public interface Phone {
void makeCall();
}
public class PhoneImpl implements Phone{
@Override
public void makeCall() {
System.out.println("call");
}
}
3.2 组合模式
组合模式将多个单体的对象组合成具有统一行为的合集
public abstract class Composite {
protected String name;
public Composite(String name) {
this.name = name;
}
public abstract void makeCall();
}
public class CompositeLeaf extends Composite {
public CompositeLeaf(String name) {
super(name);
}
@Override
public void makeCall() {
System.out.println(name);
}
}
public class CompositeRoot extends Composite {
private List<Composite> composites = new ArrayList<>();
public CompositeRoot(String name) {
super(name);
}
@Override
public void makeCall() {
if(composites != null){
composites.forEach(Composite::makeCall);
}
}
public void add(Composite child){
composites.add(child);
}
public void remove(Composite child){
composites.remove(child);
}
public Composite get(int index){
return composites.get(index);
}
}