设计模式总结
一、设计原则
1.开闭原则
对扩展开放,对修改关闭。面向抽象编程。
2.依赖倒置原则
高层模块不应该依赖底层模块,两者都应该依赖其抽象。面向接口编程。
3.单一职责原则
一个类/接口/方法只有一种引起它变更的原因,要求接口、方法做到单一职责原则。
4.接口隔离原则
接口拆分要适度。
5.迪米特法则(最少知道原则)
一个对象应该对其他对象保持最少的了解,尽量降低类与类之间的耦合性。
6.里式替换原则
所有引用基类(父类)的地方必须能透明地使用其子类的对象。
7.合成/复用原则(组合/复用原则)
尽量使用对象组合,而不是继承来达到复用的目的。
二、创建型
1.简单工厂模式
简单工厂模式通常是一个工厂类 XxxFactory
,里面有一个(静态)方法,根据我们不同的参数,返回不同的派生自同一个父类(或实现同一接口)的实例对象。
(1)实例
public abstract class Video {
public abstract void produce();
}
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("录制Java课程视频");
}
}
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("录制Python课程视频");
}
}
// 简单工厂
public class VideoFactory {
// 使用反射,便与扩展
public Video getVideo(Class<? extends Video> clazz) {
Video video = null;
try {
video = (Video) Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
return video;
}
public Video getVideo(String type) {
if ("java".equalsIgnoreCase(type)) {
return new JavaVideo();
} else if ("python".equalsIgnoreCase(type)) {
return new PythonVideo();
} else {
return null;
}
}
}
// 测试
public class Test {
public static void main(String[] args) {
// VideoFactory videoFactory = new VideoFactory();
// Video video = videoFactory.getVideo("java");
// video.produce();
VideoFactory videoFactory = new VideoFactory();
Video video = videoFactory.getVideo(PythonVideo.class);
if (video == null) {
return;
}
video.produce();
}
}
(2)应用
java.util.Calendar.createCalendar
方法中的简单工厂应用:
// 代码片段
Calendar cal = null;
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
if (cal == null) {
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
}
return cal;
2.工厂方法模式
定义一个创建对象的接口,但让实现这个接口的类决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。适用于同一产品等级。
(1)实例
public abstract class Video {
public abstract void produce();
}
// 创建对象的接口
public abstract class VideoFactory {
public abstract Video geVideo();
}
public class FEVideo extends Video {
@Override
public void produce() {
System.out.println("录制FE课程视频");
}
}
public class FEVideoFactory extends VideoFactory {
@Override
public Video geVideo() {
return new FEVideo();
}
}
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("录制Java课程视频");
}
}
public class JavaVideoFactory extends VideoFactory {
@Override
public Video geVideo() {
return new JavaVideo();
}
}
// 测试
// 同一产品等级,使用工厂方法
public class Test {
public static void main(String[] args) {
VideoFactory videoFactory = new JavaVideoFactory();
VideoFactory videoFactory2 = new FEVideoFactory();
Video video = videoFactory.geVideo();
video.produce();
}
}
(2)应用
slf4j与logback:
工厂方法:org.slf4j.ILoggerFactory.getLogger
// slf4j
public interface ILoggerFactory {
public Logger getLogger(String name);
}
工厂实现:ch.qos.logback.classic.LoggerContext
// logback
public final Logger getLogger(final String name) {
//...
if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
return root;
}
int i = 0;
Logger logger = root;
Logger childLogger = (Logger) loggerCache.get(name);
if (childLogger != null) {
return childLogger;
}
String childName;
while (true) {
int h = LoggerNameUtil.getSeparatorIndexOf(name, i);
if (h == -1) {
childName = name;
} else {
childName = name.substring(0, h);
}
i = h + 1;
synchronized (logger) {
childLogger = logger.getChildByName(childName);
if (childLogger == null) {
childLogger = logger.createChildByName(childName);
loggerCache.put(childName, childLogger);
incSize();
}
}
logger = childLogger;
if (h == -1) {
return childLogger;
}
}
}
抽象产品:org.slf4j.Logger
具体产品:ch.qos.logback.classic.Logger
3.抽象工厂模式
抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口。(产品族)
(1)实例
// 抽象工厂
public interface CourseFactory {
Video getVideo(); // 获取视频
Article getArticle(); // 获取手记
}
public abstract class Video {
public abstract void produce();
}
public abstract class Article {
public abstract void produce();
}
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("录制Java课程视频");
}
}
public class JavaArticle extends Article {
@Override
public void produce() {
System.out.println("录制Java课程手记");
}
}
public class JavaCourseFactory implements CourseFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
@Override
public Article getArticle() {
return new JavaArticle();
}
}
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("录制Python课程视频");
}
}
public class PythonArticle extends Article {
@Override
public void produce() {
System.out.println("录制Python课程手记");
}
}
public class PythonCourseFactory implements CourseFactory {
@Override
public Video getVideo() {
return new PythonVideo();
}
@Override
public Article getArticle() {
return new PythonArticle();
}
}
// 同一产品簇,使用抽象工厂
public class Test {
public static void main(String[] args) {
CourseFactory courseFactory = new JavaCourseFactory();
Video video = courseFactory.getVideo();
Article article = courseFactory.getArticle();
video.produce();
article.produce();
}
}
(2)应用
org.apache.ibatis.session.SqlSessionFactory:
public interface SqlSessionFactory {
SqlSession openSession(); // 获取SqlSession
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration(); // 获取配置
}
4.建造者模式
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。用户只需指定需要创建的类型就可以得到它们,建造过程和细节不需要知道。
(1)实例
import lombok.Builder;
// 建造者设计模式
//@Builder
public class User {
private String name;
private String password;
private String nickname;
private int age;
private User(String name, String password, String nickname, int age) {
this.name = name;
this.password = password;
this.nickname = nickname;
this.age = age;
}
// Builder
public static UserBuilder builder() {
return new UserBuilder();
}
public static class UserBuilder {
private String name;
private String password;
private String nickname;
private int age;
private UserBuilder() {
}
public UserBuilder name(String name) {
this.name = name;
return this;
}
public UserBuilder password(String password) {
this.password = password;
return this;
}
public UserBuilder nickname(String nickname) {
this.nickname = nickname;
return this;
}
public UserBuilder age(int age) {
this.age = age;
return this;
}
public User build() {
if (name == null || password == null) {
throw new RuntimeException("用户名和密码必填");
}
if (age <= 0 || age >= 150) {
throw new RuntimeException("年龄不合法");
}
// 还可以做赋予”默认值“的功能
if (nickname == null) {
nickname = name;
}
return new User(name, password, nickname, age);
}
}
}
public class Test {
public static void main(String[] args){
User u = User.builder()
.name("foo")
.age(25)
.password("pass12345")
.build();
}
}
(2)应用
- JDK:
- StringBuilder
- StringBuffer
- Guava:
- ImmutableSet
- CacheBuilder
5.单例模式
(1)懒汉式1
// 同步锁synchronized
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() {
// 无法阻止反射攻击
if (instance != null) {
throw new RuntimeException("单例构造器禁用反射调用");
}
}
public synchronized static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
(2)懒汉式2
// 双重检查+volatile
public class LazyDoubleCheckSingleton {
private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
private LazyDoubleCheckSingleton() {
}
public static LazyDoubleCheckSingleton getInstance() {
if (lazyDoubleCheckSingleton == null) {
synchronized (LazyDoubleCheckSingleton.class) {
if (lazyDoubleCheckSingleton == null) {
lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
//1.分配内存给这个对象
// //3.设置lazyDoubleCheckSingleton 指向刚分配的内存地址
//2.初始化对象
// intra-thread semantics
// ---------------//3.设置lazyDoubleCheckSingleton 指向刚分配的内存地址
}
}
}
return lazyDoubleCheckSingleton;
}
}
(3)静态嵌套类
// 静态嵌套类单例
public class StaticNestedClassSingleton {
// 静态嵌套类可以访问外围类的静态属性和方法
private static class StaticNestedClass {
private static StaticNestedClassSingleton staticNestedClassSingleton = new StaticNestedClassSingleton();
}
public static StaticNestedClassSingleton getInstance() {
return StaticNestedClass.staticNestedClassSingleton; // 初始化
}
private StaticNestedClassSingleton() {
// 防止反射攻击
if (StaticNestedClass.staticNestedClassSingleton != null) {
throw new RuntimeException("单例构造器禁用反射调用");
}
}
}
(4)饿汉式
// 饿汉式单例
public class HungrySingleton implements Serializable, Cloneable {
private static final HungrySingleton instance;
static {
instance = new HungrySingleton();
}
public static HungrySingleton getInstance() {
return instance;
}
private HungrySingleton() {
// 防止反射攻击
if (instance != null) {
throw new RuntimeException("单例构造器禁用反射调用");
}
}
// 防止序列化与反序列化破坏单例模式
private Object readResolve() {
return instance;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// return super.clone();
return getInstance();
}
}
(5)容器单例
// 容器单例,非线程安全。适合在类初始化的时候使用,维护很多单例
public class ContainerSingleton {
private ContainerSingleton() {
}
private static Map<String, Object> singletonMap = new HashMap<>();
public static void putInstance(String key, Object instance) {
if (StringUtils.isNotBlank(key) && instance != null) {
if (!singletonMap.containsKey(key)) {
singletonMap.put(key, instance);
}
}
}
public static Object getInstance(String key) {
return singletonMap.get(key);
}
}
(6)枚举单例
// 枚举单例
public enum EnumSingleton {
INSTANCE{
@Override
protected void printTest() {
System.out.println("print test jat,,,");
}
};
protected abstract void printTest();
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumSingleton getInstance() {
return INSTANCE;
}
}
(7)ThreadLocalSingleton
// 线程内单例
public class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> THREAD_LOCAL_SINGLETON_THREAD_LOCAL
= new ThreadLocal<ThreadLocalSingleton>() {
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};
private ThreadLocalSingleton() {
}
public static ThreadLocalSingleton getInstance() {
return THREAD_LOCAL_SINGLETON_THREAD_LOCAL.get();
}
}
(8)应用
java.lang.Runtime.getRuntime
饿汉式
public class Runtime {
private static Runtime currentRuntime = new Runtime();
private Runtime() {}
public static Runtime getRuntime() {
return currentRuntime;
}
}
6.原型模式
原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
(1)实例
// 抽象类
public abstract class A implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// 实现类
public class B extends A {
public static void main(String[] args) throws CloneNotSupportedException {
B b = new B();
B b2 = (B) b.clone();
System.out.println(b);
System.out.println(b2);
}
}
// 深拷贝与浅拷贝
public class Pig implements Cloneable {
private String name;
private Date birthday;
public Pig(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Pig{" +
"name='" + name + '\'' +
", birthday=" + birthday +
'}' + "--" + super.toString();
}
// 浅拷贝
// @Override
// protected Object clone() throws CloneNotSupportedException {
// return super.clone();
// }
@Override
protected Object clone() throws CloneNotSupportedException {
// 深拷贝
Pig pig = (Pig) super.clone();
pig.birthday = (Date) pig.birthday.clone();
return pig;
}
}
(2)应用
ArrayList
:
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size); // 元素引用相同
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
三、结构型
1.外观模式
又叫门面模式,提供了一个统一的接口(外观类),用来访问子系统的一群接口。包含外观类、子系统、客户端三部分。
(1)实例
// 积分兑换的礼物
public class PointGift {
private String name;
public PointGift(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// 校验子系统
public class QualifyService {
public boolean isAvailable(PointGift pointGift) {
System.out.println("校验 " + pointGift.getName() + " 积分资格通过, 库存通过");
return true;
}
}
// 扣减积分子系统
public class PointPaymentService {
public boolean pay(PointGift pointGift) {
// 扣减积分
System.out.println("支付 " + pointGift.getName() + " 积分成功");
return true;
}
}
// 物流子系统
public class ShippingService {
public String shipGift(PointGift pointGift) {
// 物流系统的对接逻辑
System.out.println(pointGift.getName() + " 进入物流系统");
String shippingOrderNo = "666";
return shippingOrderNo;
}
}
// 外观类
public class GiftExchangeService {
private QualifyService qualifyService = new QualifyService();
private PointPaymentService pointPaymentService = new PointPaymentService();
private ShippingService shippingService = new ShippingService();
public void giftExchange(PointGift pointGift) {
if (qualifyService.isAvailable(pointGift)) {
// 资格校验通过
if (pointPaymentService.pay(pointGift)) {
// 积分支付通过
String shippingOrderNo = shippingService.shipGift(pointGift);
System.out.println("物流系统下单成功,订单号是: " + shippingOrderNo);
}
}
}
}
// 客户端
public class Test {
public static void main(String[] args) {
PointGift pointGift = new PointGift("T恤");
// 外观对象
GiftExchangeService giftExchangeService = new GiftExchangeService();
giftExchangeService.giftExchange(pointGift);
}
}
(2)应用
org.springframework.jdbc.support.JdbcUtils
:
public static void closeConnection(Connection con) {
if (con != null) {
try {
con.close();
}
catch (SQLException ex) {
logger.debug("Could not close JDBC Connection", ex);
}
catch (Throwable ex) {
// We don't trust the JDBC driver: It might throw RuntimeException or Error.
logger.debug("Unexpected exception on closing JDBC Connection", ex);
}
}
}
2.装饰者模式
在不改变原有对象的基础上,将功能附加到对象之上。提供了比继承更具弹性的替代方案。(扩展了原有对象的功能)
(1)实例
// 抽象被装饰者
public 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 8;
}
}
// 抽象装饰者
public abstract class AbstractDecorator extends ABattercake {
private ABattercake aBattercake;
public AbstractDecorator(ABattercake aBattercake) {
this.aBattercake = aBattercake;
}
protected abstract void doSomething();
@Override
protected String getDesc() {
return this.aBattercake.getDesc();
}
@Override
protected int cost() {
return this.aBattercake.cost();
}
}
// 具体装饰者1
public class EggDecorator extends AbstractDecorator {
public EggDecorator(ABattercake aBattercake) {
super(aBattercake);
}
@Override
protected void doSomething() {
}
@Override
protected String getDesc() {
return super.getDesc() + ", 加鸡蛋";
}
@Override
protected int cost() {
return super.cost() + 1;
}
}
// 具体装饰者2
public class SausageDecorator extends AbstractDecorator {
public SausageDecorator(ABattercake aBattercake) {
super(aBattercake);
}
@Override
protected void doSomething() {
}
@Override
protected String getDesc() {
return super.getDesc() + ", 加香肠";
}
@Override
protected int cost() {
return super.cost() + 2;
}
}
// 测试
public class Test {
public static void main(String[] args) {
ABattercake aBattercake = new Battercake();
aBattercake = new EggDecorator(aBattercake); // 加鸡蛋
aBattercake = new EggDecorator(aBattercake); // 加鸡蛋
aBattercake = new SausageDecorator(aBattercake); // 再加香肠
System.out.println(aBattercake.getDesc() + " 销售价格: " + aBattercake.cost());
}
}
// 煎饼, 加鸡蛋, 加鸡蛋, 加香肠 销售价格: 12
UML图:
(2)应用
Java IO中的装饰者模式应用:
DataInputStream is = new DataInputStream(
new BufferedInputStream(
new FileInputStream("demo.txt")));
3.适配器模式
将一个类的接口转换成客户期望的另一个借口。使原本不兼容的类可以一起工作。有默认适配器、类适配器和对象适配器三种。
(1)默认适配器
// 目标接口,方法太多
public interface FileAlterationListener {
void onStart(final FileAlterationObserver observer);
void onDirectoryCreate(final File directory);
void onDirectoryChange(final File directory);
void onDirectoryDelete(final File directory);
void onFileCreate(final File file);
void onFileChange(final File file);
void onFileDelete(final File file);
void onStop(final FileAlterationObserver observer);
}
// 默认适配器,实现所有接口方法,方法体为空
public class FileAlterationListenerAdapter implements FileAlterationListener {
@Override
public void onStart(FileAlterationObserver observer) {
}
@Override
public void onDirectoryCreate(File directory) {
}
@Override
public void onDirectoryChange(File directory) {
}
@Override
public void onDirectoryDelete(File directory) {
}
@Override
public void onFileCreate(File file) {
}
@Override
public void onFileChange(File file) {
}
@Override
public void onFileDelete(File file) {
}
@Override
public void onStop(FileAlterationObserver observer) {
}
}
// 接口实现类按需重写Adapter类方法
public class FileMonitor extends FileAlterationListenerAdapter {
@Override
public void onFileCreate(File file) {
// 文件创建
}
@Override
public void onFileDelete(File file) {
// 文件删除
}
}
(2)类适配器
// 被适配者
public class Adaptee {
public void adapteeRequest() {
System.out.println("被适配者的方法");
}
}
// 目标
public interface Target {
void request();
}
// 类适配器,通过类继承的方式
public class Adapter extends Adaptee implements Target {
@Override
public void request() {
// do something else...
super.adapteeRequest();
// do something else...
}
}
(3)对象适配器
// 被适配者
public class Adaptee {
public void adapteeRequest() {
System.out.println("被适配者的方法");
}
}
// 目标
public interface Target {
void request();
}
// 对象适配器,通过对象组合的方式
public class Adapter implements Target {
// 对象组合
private Adaptee adaptee = new Adaptee();
@Override
public void request() {
// do something else...
adaptee.adapteeRequest();
// do something else...
}
}
(4)应用
// Executors方法,将Runnable实例适配成Callable实例
public static Callable<Object> callable(Runnable task) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<Object>(task, null);
}
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}
4.享元模式(对象复用)
提供了减少对象数量从而改善应用所需的对象结构的方式。减少对象的创建(缓存),降低内存中对象的数量。
(1)实例
// 员工
public interface Employee {
void report();
}
// 经理
public class Manager implements Employee {
@Override
public void report() {
System.out.println(reportContent);
}
// 内部状态
private String title = "部门经理";
// 外部状态
private String reportContent;
private String department;
public Manager(String department) {
this.department = department;
}
public void setReportContent(String reportContent) {
this.reportContent = reportContent;
}
}
// 员工工厂,简单工厂
public class EmployeeFactory {
// 容器单例
private static final Map<String, Employee> EMPLOYEE_MAP = new HashMap<>(16);
public static Employee getManager(String department) {
Manager manager = (Manager) EMPLOYEE_MAP.get(department);
if (manager == null) {
manager = new Manager(department);
System.out.print("创建部门经理:" + department);
String reportContent = department+"部门汇报:此次报告的主要内容是......";
manager.setReportContent(reportContent);
System.out.println(" 创建报告:" + reportContent);
EMPLOYEE_MAP.put(department, manager);
}
return manager;
}
}
(2)应用
java.lang.Integer.valueOf(int)
// 首先判断i是否在-128到127之间,是则从缓存中取出Integer对象;否则创建对象
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
5.组合模式
将对象组合成树形结构以表示”部分—整体”的层次结构。组合模式使客户端对单个对象和组合对象保持一致的方式处理。(递归结构)
(1)实例
// 公共的抽象父类或接口
public abstract class CatalogComponent {
public void add(CatalogComponent catalogComponent) {
throw new UnsupportedOperationException("不支持添加操作");
}
public void remove(CatalogComponent catalogComponent) {
throw new UnsupportedOperationException("不支持删除操作");
}
public String getName(CatalogComponent catalogComponent) {
throw new UnsupportedOperationException("不支持获取名称操作");
}
public double getPrice(CatalogComponent catalogComponent) {
throw new UnsupportedOperationException("不支持获取价格操作");
}
// 1 print方法不需要参数
public void print() {
throw new UnsupportedOperationException("不支持打印操作");
}
}
// 目录课程
public class Course extends CatalogComponent {
private String name;
private double price;
public Course(String name, double price) {
this.name = name;
this.price = price;
}
// 2 重写需要的方法
@Override
public String getName(CatalogComponent catalogComponent) {
return this.name;
}
@Override
public double getPrice(CatalogComponent catalogComponent) {
return this.price;
}
@Override
public void print() {
System.out.println("Course name: " + name + ", Price: " + price);
}
}
// 课程目录
public class CourseCatalog extends CatalogComponent {
private List<CatalogComponent> components = new ArrayList<>();
private String name;
private Integer level; // 3 目录级别,控制缩进
public CourseCatalog(String name, Integer level) {
this.name = name;
this.level = level;
}
@Override
public void add(CatalogComponent catalogComponent) {
components.add(catalogComponent);
}
@Override
public void remove(CatalogComponent catalogComponent) {
components.remove(catalogComponent);
}
@Override
public String getName(CatalogComponent catalogComponent) {
return this.name;
}
@Override
public void print() {
System.out.println(this.name);
components.forEach(component -> {
if (level != null) {
for (Integer i = 0; i < level; i++) {
System.out.print(" ");
}
}
component.print();
});
}
}
// 组合模式测试
public class Test {
public static void main(String[] args) {
CatalogComponent linuxCourse = new Course("Linux", 11);
CatalogComponent windowsCourse = new Course("Windows", 11);
CatalogComponent javaCourseCatalog = new CourseCatalog("Java课程目录", 2);
CatalogComponent mmall1 = new Course("Java电商1期", 30);
CatalogComponent mmall2 = new Course("Java电商2期", 30);
CatalogComponent javaDesignPattern = new Course("Java设计模式", 40);
javaCourseCatalog.add(mmall1);
javaCourseCatalog.add(mmall2);
javaCourseCatalog.add(javaDesignPattern);
CatalogComponent imoocMainCatalog = new CourseCatalog("慕课网课程主目录", 1);
imoocMainCatalog.add(linuxCourse);
imoocMainCatalog.add(windowsCourse);
imoocMainCatalog.add(javaCourseCatalog);
imoocMainCatalog.print();
}
}
// 输出
慕课网课程主目录
Course name: Linux, Price: 11.0
Course name: Windows, Price: 11.0
Java课程目录
Course name: Java电商1期, Price: 30.0
Course name: Java电商2期, Price: 30.0
Course name: Java设计模式, Price: 40.0
(2)应用
org.apache.ibatis.scripting.xmltags.MixedSqlNode
public class MixedSqlNode implements SqlNode {
private List<SqlNode> contents;
public MixedSqlNode(List<SqlNode> contents) {
this.contents = contents;
}
@Override
public boolean apply(DynamicContext context) {
for (SqlNode sqlNode : contents) {
sqlNode.apply(context);
}
return true;
}
}
6.桥接模式
将抽象部分和它的具体实现部分分离,使他们都可以独立地变化。通过组合的方式建立两个类之间的联系,而不是继承。
(1)实例
// 具体实现
public interface DrawAPI {
void draw(int radius, int x, int y);
}
public class GreenPen implements DrawAPI {
@Override
public void draw(int radius, int x, int y) {
System.out.println("用绿色笔画图,radius:" + radius + ", x:" + x + ", y:" + y);
}
}
public class RedPen implements DrawAPI {
@Override
public void draw(int radius, int x, int y) {
System.out.println("用红色笔画图,radius:" + radius + ", x:" + x + ", y:" + y);
}
}
// 抽象部分
public abstract class Shape {
protected DrawAPI drawAPI; // 组合的方式
protected Shape(DrawAPI drawAPI) {
this.drawAPI = drawAPI;
}
protected abstract void draw();
}
// 圆
public class Circle extends Shape {
private int radius;
public Circle(int radius, DrawAPI drawAPI) {
super(drawAPI);
this.radius = radius;
}
@Override
protected void draw() {
System.out.println("画一个圆");
drawAPI.draw(radius, 0, 0);
}
}
// 长方形
public class Rectangle extends Shape {
private int x;
private int y;
protected Rectangle(int x, int y, DrawAPI drawAPI) {
super(drawAPI);
this.x = x;
this.y = y;
}
@Override
protected void draw() {
System.out.println("画一个长方形");
drawAPI.draw(0, x, y);
}
}
// 测试
public class Test {
public static void main(String[] args) {
Shape greenCircle = new Circle(10, new GreenPen());
greenCircle.draw();
Shape redRectangle = new Rectangle(4, 8, new RedPen());
redRectangle.draw();
}
}
// 输出
画一个圆
用绿色笔画图,radius:10, x:0, y:0
画一个长方形
用红色笔画图,radius:0, x:4, y:8
(2)应用
JDBC java.sql.DriverManager
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
DriverInfo---java.sql.Driver 不同厂商、不同的Driver实现。DriverManager 与Driver是桥接模式
7.代理模式
分为静态代理和动态代理。
(1)准备场景
// 订单
public class Order {
private Object orderInfo;
private int userId;
public Object getOrderInfo() {
return orderInfo;
}
public void setOrderInfo(Object orderInfo) {
this.orderInfo = orderInfo;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
}
// 订单服务
public interface IOrderService {
int saveOrder(Order order);
}
// 订单Dao
public interface IOrderDao {
int insertOrder(Order order);
}
// 订单服务实现
public class OrderServiceImpl implements IOrderService {
// Spring注入
private IOrderDao orderDao;
@Override
public int saveOrder(Order order) {
System.out.println("OrderService调用OrderDao,将Order保存到数据库");
// Spring注入,这里直接new
orderDao = new OrderDaoImpl();
return orderDao.insertOrder(order);
}
}
// OrderDao实现
public class OrderDaoImpl implements IOrderDao {
@Override
public int insertOrder(Order order) {
System.out.println("OrderDao插入Order到数据库成功");
return 1;
}
}
public class DataSourceContextHolder {
private static final ThreadLocal<String> CONTEXT_HOOLDER = new ThreadLocal<>();
public static void setDBtype(String dbType) {
CONTEXT_HOOLDER.set(dbType);
}
public strictfp String getDBType() {
return CONTEXT_HOOLDER.get();
}
public static void clearDBType() {
CONTEXT_HOOLDER.remove();
}
}
(2)静态代理
// OrderService静态代理
public class OrderServiceStaticProxy implements IOrderService {
private IOrderService orderService;
public OrderServiceStaticProxy(IOrderService orderService) {
this.orderService = orderService;
}
@Override
public int saveOrder(Order order) {
beforeMethod(order); // 增强
int result = orderService.saveOrder(order);
afterMethod(order); // 增强
return result;
}
private void beforeMethod(Order order) {
int userId = order.getUserId();
int daRouter = userId % 2;
System.out.println("静态代理分配到[db" + daRouter + "]处理数据");
// 设置DataSource
DataSourceContextHolder.setDBtype("db" + daRouter);
System.out.println("静态代理before code");
}
private void afterMethod(Order order) {
System.out.println("静态代理after code");
}
}
// 静态代理测试
public class Test {
public static void main(String[] args) {
Order order = new Order();
order.setUserId(2);
OrderServiceStaticProxy serviceStaticProxy = new OrderServiceStaticProxy(new OrderServiceImpl());
serviceStaticProxy.saveOrder(order);
}
}
(3)动态代理
// 动态代理handler,具有创建代理的功能
public class OrderServiceDynamicProxy implements InvocationHandler {
// 被代理对象,OrderServiceImpl
private Object target;
public OrderServiceDynamicProxy(Object target) {
this.target = target;
}
// 创建代理对象
public Object build() {
Class clazz = target.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object arg = args[0];
beforeMethod(arg); // 增强
Object result = method.invoke(target, args);
afterMethod(); // 增强
return result;
}
private void beforeMethod(Object arg) {
System.out.println("动态代理before code");
int userId = 0;
if (arg instanceof Order) {
userId = ((Order) arg).getUserId();
}
int daRouter = userId % 2;
System.out.println("动态代理分配到[db" + daRouter + "]处理数据");
// 设置DataSource
DataSourceContextHolder.setDBtype("db" + daRouter);
}
private void afterMethod() {
System.out.println("动态代理after code");
}
}
// 动态代理测试
public class Test {
public static void main(String[] args) {
Order order = new Order();
// order.setUserId(1);
order.setUserId(2);
// 创建代理
IOrderService orderService = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).build();
orderService.saveOrder(order);
}
}
四、行为型
行为型模式关注的是各个类之间的相互作用,将职责划分清楚,使得我们的代码更加地清晰。
1.模板方法模式
定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现。使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。
(1)实例
// 模板
public abstract class AbstractCourse {
// 算法流程固定,不允许修改 final
protected final void makeCourse() {
this.makePPT();
this.makeVedio();
if (needWriteArticle()) { // 控制
this.writeActicle();
}
packageCourse(); // 完全由子类实现
}
final void makePPT() {
System.out.println("制作PPT");
}
final void makeVedio() {
System.out.println("制作视频");
}
// 钩子方法
final void writeActicle() {
System.out.println("写手记");
}
protected boolean needWriteArticle() {
return false;
}
protected abstract void packageCourse();
}
// 设计模式课程,课程级别
public class DesignPatternCourse extends AbstractCourse {
@Override
protected void packageCourse() {
System.out.println("提供课程Java源代码");
}
@Override
protected boolean needWriteArticle() {
return true;
}
}
// 前端课程,大范围
public class FECourse extends AbstractCourse {
private boolean needWriteArticleFlag = false;
public FECourse(boolean needWriteArticleFlag) {
this.needWriteArticleFlag = needWriteArticleFlag;
}
@Override
protected void packageCourse() {
System.out.println("提供课程的前端代码");
System.out.println("提供课程的图片等多媒体素材");
}
@Override
protected boolean needWriteArticle() {
return needWriteArticleFlag;
}
}
public class Test {
public static void main(String[] args) {
System.out.println("后端设计模式课程start---");
AbstractCourse designPatternCourse = new DesignPatternCourse();
designPatternCourse.makeCourse();
System.out.println("后端设计模式课程end---");
System.out.println("-------------------------");
System.out.println("前端课程start---");
AbstractCourse feCourse = new FECourse(false);
feCourse.makeCourse();
System.out.println("前端课程end---");
}
}
// 输出
后端设计模式课程start---
制作PPT
制作视频
写手记
提供课程Java源代码
后端设计模式课程end---
-------------------------
前端课程start---
制作PPT
制作视频
提供课程的前端代码
提供课程的图片等多媒体素材
前端课程end---
(2)应用
AbstractList、AbstractMap、AbstractSet
javax.servlet.http.HttpServlet--doGet() doPost()...
org.apache.ibatis.executor.BaseExecutor--doUpdate() doQuery()
2.迭代器模式
提供一种方法,顺序访问一个集合对象中的各个元素,而又不暴露该对象的内部表示。为遍历不同的集合结构提供统一的接口。
(1)实例
// 课程
public class Course {
private String name;
public Course(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// 课程迭代器
public interface CourseIterator {
boolean hasNextCourse();
Course nextCourse();
}
public class CourseIteratorImpl implements CourseIterator {
private List<Course> courses;
private int position;
public CourseIteratorImpl(List<Course> courses) {
this.courses = courses;
}
@Override
public boolean hasNextCourse() {
return position < courses.size();
}
@Override
public Course nextCourse() {
System.out.println("返回课程,位置是: " + position);
Course course = courses.get(position);
position++;
return course;
}
}
// 课程集合
public interface CourseAggregate {
void addCourse(Course course);
void removeCourse(Course course);
CourseIterator getCourseIterator();
}
public class CourseAggregateImpl implements CourseAggregate {
private List<Course> courses;
public CourseAggregateImpl() {
this.courses = new ArrayList<>();
}
@Override
public void addCourse(Course course) {
courses.add(course);
}
@Override
public void removeCourse(Course course) {
courses.remove(course);
}
@Override
public CourseIterator getCourseIterator() {
return new CourseIteratorImpl(courses);
}
}
// 测试
public class Test {
public static void main(String[] args) {
Course course1 = new Course("Java电商一期");
Course course2 = new Course("Java电商二期");
Course course3 = new Course("Java设计模式精讲");
Course course4 = new Course("Python课程");
Course course5 = new Course("算法课程");
Course course6 = new Course("前端课程");
CourseAggregate courseAggregate = new CourseAggregateImpl();
courseAggregate.addCourse(course1);
courseAggregate.addCourse(course2);
courseAggregate.addCourse(course3);
courseAggregate.addCourse(course4);
courseAggregate.addCourse(course5);
courseAggregate.addCourse(course6);
System.out.println("-----课程列表-----");
printCourses(courseAggregate);
courseAggregate.removeCourse(course4);
courseAggregate.removeCourse(course5);
System.out.println("-----删除操作之后的课程列表-----");
printCourses(courseAggregate);
}
public static void printCourses(CourseAggregate courseAggregate){
CourseIterator courseIterator= courseAggregate.getCourseIterator();
while(courseIterator.hasNextCourse()){
Course course=courseIterator.nextCourse();
System.out.println(course.getName());
}
}
}
// 输出
-----课程列表-----
返回课程,位置是: 0
,
返回课程,位置是: 1
Java电商二期
返回课程,位置是: 2
Java设计模式精讲
返回课程,位置是: 3
Python课程
返回课程,位置是: 4
算法课程
返回课程,位置是: 5
前端课程
-----删除操作之后的课程列表-----
返回课程,位置是: 0
,
返回课程,位置是: 1
Java电商二期
返回课程,位置是: 2
Java设计模式精讲
返回课程,位置是: 3
前端课程
(2)应用
java.util.ArrayList.Itr
java.util.ArrayList.ListItr
3.策略模式
定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化不会影响到使用算法的用户。
适用于替换if…else…
(1)实例
// 促销策略抽象
public interface PromotionStrategy {
void doPromotion();
}
public class FanXianPromotionStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("返现促销,返回的金额存放到用户的余额中");
}
}
public class LiJianPromotionStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("立减促销,课程的价格直接减去配置的价格");
}
}
public class ManJianPromotionStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("满减促销,满200-20元");
}
}
public class EmptyPromotionStrategy implements PromotionStrategy {
@Override
public void doPromotion() {
System.out.println("无促销");
}
}
// 促销活动,使用促销策略
public class PromotionActivity {
private PromotionStrategy promotionStrategy;
public PromotionActivity(PromotionStrategy promotionStrategy) {
this.promotionStrategy = promotionStrategy;
}
public void executePromotionStrategy() {
promotionStrategy.doPromotion();
}
}
// 促销策略工厂
public class PromotionStrategyFactory {
private static final Map<String, PromotionStrategy> PROMOTION_STRATEGY_MAP =
new HashMap<>(8);
static {
PROMOTION_STRATEGY_MAP.put(PromotionKey.FANXIAN, new FanXianPromotionStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKey.LIJIAN, new LiJianPromotionStrategy());
PROMOTION_STRATEGY_MAP.put(PromotionKey.MANJIAN, new ManJianPromotionStrategy());
}
private static final PromotionStrategy NON_PROMOTION = new EmptyPromotionStrategy();
private PromotionStrategyFactory() {
}
public static PromotionStrategy getPromotionStrategy(String promotionKey) {
PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey);
return promotionStrategy == null ? NON_PROMOTION : promotionStrategy;
}
interface PromotionKey {
String LIJIAN = "LIJIAN";
String MANJIAN = "MANJIAN";
String FANXIAN = "FANXIAN";
}
}
// 测试
public class Test {
public static void main(String[] args) {
String promotionKey = "MANJIAN";
PromotionActivity promotionActivity =
new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey));
promotionActivity.executePromotionStrategy();
}
}
(2)应用
比较器java.util.Comparator,不同比较器有不同的比较策略。
Spring资源抽象org.springframework.core.io.Resource
4.解释器模式
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。为了解释一种语言,而为语言创建的解释器。
(1)实例
// 解释器
public interface Interpreter {
int interpret();
}
// 加法解释器
public class AddInterpreter implements Interpreter {
private Interpreter firstExpression, secondExpresion;
public AddInterpreter(Interpreter firstExpression, Interpreter secondExpresion) {
this.firstExpression = firstExpression;
this.secondExpresion = secondExpresion;
}
@Override
public int interpret() {
return firstExpression.interpret() + secondExpresion.interpret();
}
@Override
public String toString() {
return "+";
}
}
// 乘法解释器
public class MultiInterpreter implements Interpreter {
private Interpreter firstExpression, secondExpresion;
public MultiInterpreter(Interpreter firstExpression, Interpreter secondExpresion) {
this.firstExpression = firstExpression;
this.secondExpresion = secondExpresion;
}
@Override
public int interpret() {
return firstExpression.interpret() * secondExpresion.interpret();
}
@Override
public String toString() {
return "*";
}
}
// 空解释器
public class EmptyInterpreter implements Interpreter {
@Override
public int interpret() {
return 0;
}
}
// 数字
public class NumberInterpreter implements Interpreter {
private int number;
public NumberInterpreter(int number) {
this.number = number;
}
public NumberInterpreter(String number) {
this.number = Integer.parseInt(number);
}
@Override
public int interpret() {
return this.number;
}
}
// 自定义表达式解析器
public class GeelyExpressionParser {
private Stack<Interpreter> stack = new Stack<>();
public int parse(String str) {
String[] items = str.split(" ");
for (String symbol : items) {
if (!OperationUtil.isOperator(symbol)) {
Interpreter numberExpression = new NumberInterpreter(symbol);
stack.push(numberExpression);
System.out.printf("入栈:%d\n", numberExpression.interpret());
} else {
Interpreter firstExpression = stack.pop();
Interpreter secondExpression = stack.pop();
System.out.printf("出栈:%d 和 %d\n", firstExpression.interpret(), secondExpression.interpret());
Interpreter operator = OperationUtil.getExpressionObject(symbol, firstExpression, secondExpression);
System.out.printf("应用运算符 %s\n", operator);
int result = operator.interpret();
NumberInterpreter numberExpression = new NumberInterpreter(result);
stack.push(numberExpression);
System.out.printf("阶段结果入栈:%d\n", numberExpression.interpret());
}
}
return stack.pop().interpret();
}
}
// 操作符工具类
public class OperationUtil {
public static boolean isOperator(String symbol) {
return "+".equals(symbol) || "*".equals(symbol);
}
public static Interpreter getExpressionObject(String symbol, Interpreter firstExpression, Interpreter secondExpression) {
if ("*".equals(symbol)) {
return new MultiInterpreter(firstExpression, secondExpression);
} else if ("+".equals(symbol)) {
return new AddInterpreter(firstExpression, secondExpression);
} else {
return new EmptyInterpreter();
}
}
}
// 解释器模式测试
public class Test {
public static void main(String[] args) {
String str = "6 100 11 + *";
GeelyExpressionParser expressionParser = new GeelyExpressionParser();
int result = expressionParser.parse(str);
System.out.println("表达式计算结果:" + result);
}
}
(2)应用
正则表达式抽象 java.util.regex.Pattern
Spring EL表达式抽象 org.springframework.expression.ExpressionParser
5.观察者模式
定义了对象之间的一对多依赖,让多个观察者对象同时监听某个主题对象,当主题对象发生变化时,它的所有依赖者(观察者)都会收到通知并更新。
(1)实例
// 课程,被观察对象
public class Course extends Observable {
private String courseName;
public Course(String courseName) {
this.courseName = courseName;
}
public String getCourseName() {
return courseName;
}
public void produceQuestion(Course course, Question question) {
System.out.println(question.getUsername() + "在" + course.getCourseName() + "提交了一个问题。");
// 设置数据变化
setChanged();
// 通知观察者
notifyObservers(question);
}
}
// 讲师,观察者
public class Teacher implements Observer {
private String teacherName;
public Teacher(String teacherName) {
this.teacherName = teacherName;
}
public String getTeacherName() {
return teacherName;
}
@Override
public void update(Observable o, Object arg) {
Course course = (Course) o;
Question question = (Question) arg;
System.out.println(teacherName + "老师的" + course.getCourseName() + "课程收到了一个"
+ question.getUsername() + "提交的问题:" + question.getQuestionContent());
}
}
// 提问题
public class Question {
private String username;
private String questionContent;
public String getUsername() {
return username;
}
public String getQuestionContent() {
return questionContent;
}
public void setUsername(String username) {
this.username = username;
}
public void setQuestionContent(String questionContent) {
this.questionContent = questionContent;
}
}
// 观察者模式测试
public class Test {
public static void main(String[] args) {
// 被观察者
Course course = new Course("Java设计模式精讲");
// 观察者
Teacher teacher = new Teacher("Alpha");
course.addObserver(teacher);
Question question = new Question();
question.setUsername("Jay");
question.setQuestionContent("Java的主函数如何编写");
// 触发数据变更
course.produceQuestion(course, question);
}
}
// 输出
Jay在Java设计模式精讲提交了一个问题。
Alpha老师的Java设计模式精讲课程收到了一个Jay提交的问题:Java的主函数如何编写
(2)应用
Guava:com.google.common.eventbus.EventBus
JDK:
java.util.Observable/java.util.Observer
java.util.EventListener
6.备忘录模式
保存一个对象的某个状态,以便在适当的时候恢复对象。为用户提供了一种可恢复机制。
实例
// 手记
public class Article {
private String title;
private String content;
private String imgs;
public Article(String title, String content, String imgs) {
this.title = title;
this.content = content;
this.imgs = imgs;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getImgs() {
return imgs;
}
public void setImgs(String imgs) {
this.imgs = imgs;
}
public ArticleMemento saveToMemento() {
return new ArticleMemento(title, content, imgs);
}
public void undoFromMemento(ArticleMemento memento) {
this.content = memento.getContent();
this.title = memento.getTitle();
this.imgs = memento.getImgs();
}
@Override
public String toString() {
return "Article{" +
"title='" + title + '\'' +
", content='" + content + '\'' +
", imgs='" + imgs + '\'' +
'}';
}
}
// 手记备忘录
public class ArticleMemento {
private String title;
private String content;
private String imgs;
public ArticleMemento(String title, String content, String imgs) {
this.title = title;
this.content = content;
this.imgs = imgs;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
public String getImgs() {
return imgs;
}
@Override
public String toString() {
return "ArticleMemento{" +
"title='" + title + '\'' +
", content='" + content + '\'' +
", imgs='" + imgs + '\'' +
'}';
}
}
// 手记备忘录 管理器
public class ArticleMementoManager {
private final Stack<ArticleMemento> articleMementoStack = new Stack<>();
public void addMemento(ArticleMemento articleMemento) {
articleMementoStack.push(articleMemento);
}
public ArticleMemento getArticleMemento() {
// 拿出的总是最新的记录
return articleMementoStack.pop();
}
}
// 备忘录模式测试
public class Test {
public static void main(String[] args) {
ArticleMementoManager articleMementoManager = new ArticleMementoManager();
Article article = new Article("如影随形的设计模式A", "手记内容A", "手记图片A");
ArticleMemento articleMemento = article.saveToMemento();
articleMementoManager.addMemento(articleMemento);
System.out.println("标题:" + article.getTitle() + " 内容:" + article.getContent() + " 图片:" + article.getImgs());
System.out.println("手记完整信息:" + article);
System.out.println("修改手记 start");
article.setTitle("如影随形的设计模式B");
article.setContent("手记内容B");
article.setImgs("手记图片B");
System.out.println("修改手记 end");
System.out.println("手记完整信息:" + article);
articleMemento = article.saveToMemento();
articleMementoManager.addMemento(articleMemento);
article.setTitle("如影随形的设计模式C");
article.setContent("手记内容C");
article.setImgs("手记图片C");
System.out.println("暂存回退start");
System.out.println("回退出栈1次");
articleMemento = articleMementoManager.getArticleMemento();
article.undoFromMemento(articleMemento);
System.out.println("回退出栈2次");
articleMemento = articleMementoManager.getArticleMemento();
article.undoFromMemento(articleMemento);
System.out.println("暂存回退end");
System.out.println("手记完整信息:" + article);
}
}
// 输出
标题:如影随形的设计模式A 内容:手记内容A 图片:手记图片A
手记完整信息:Article{title='如影随形的设计模式A', content='手记内容A', imgs='手记图片A'}
修改手记 start
修改手记 end
手记完整信息:Article{title='如影随形的设计模式B', content='手记内容B', imgs='手记图片B'}
暂存回退start
回退出栈1次
回退出栈2次
暂存回退end
手记完整信息:Article{title='如影随形的设计模式A', content='手记内容A', imgs='手记图片A'}
7.命令模式
将”请求”封装成对象,以便使用不同的请求。命令模式解决了应用程序中对象的职责以及它们之间的通信方式。
(1)实例
// 课程视频
public class CourseVedio {
private String name;
public CourseVedio(String name) {
this.name = name;
}
public void open() {
System.out.println(name + "课程视频打开");
}
public void close() {
System.out.println(name + "课程视频关闭");
}
}
// 命令
public interface Command {
void execute();
}
// 具体命令
public class OpenCourseVedioCommand implements Command {
private CourseVedio courseVedio;
public OpenCourseVedioCommand(CourseVedio courseVedio) {
this.courseVedio = courseVedio;
}
@Override
public void execute() {
courseVedio.open();
}
}
// 具体命令
public class CloseCourseVedioCommand implements Command {
private CourseVedio courseVedio;
public CloseCourseVedioCommand(CourseVedio courseVedio) {
this.courseVedio = courseVedio;
}
@Override
public void execute() {
courseVedio.close();
}
}
// 员工
public class Staff {
private List<Command> commandList = new ArrayList<>();
public void addCommand(Command command) {
commandList.add(command);
}
public void executeCommands() {
commandList.forEach(Command::execute);
commandList.clear(); // 清空命令列表
}
}
// 命令模式测试
public class Test {
public static void main(String[] args) {
CourseVedio courseVedio = new CourseVedio("Java设计模式精讲");
OpenCourseVedioCommand openCourseVedioCommand = new OpenCourseVedioCommand(courseVedio);
CloseCourseVedioCommand closeCourseVedioCommand = new CloseCourseVedioCommand(courseVedio);
Staff staff = new Staff();
// 添加命令
staff.addCommand(openCourseVedioCommand);
staff.addCommand(closeCourseVedioCommand);
// 执行命令
staff.executeCommands();
}
}
// 输出
Java设计模式精讲课程视频打开
Java设计模式精讲课程视频关闭
(2)应用
java.lang.Runnable–不同的实现,不同的Task
8.中介者模式
定义一个 封装一组对象如何交互 的对象。通过使对象明确地相互引用来促进松散耦合,并允许独立地改变它们的交互。
(1)实例
// 学习群,中介者
public class StudyGroup {
// 决定了User如何交互的行为
public static void sendMessage(User user, String message) {
System.out.println(new Date() + " [" + user.getName() + "]: " + message);
}
}
// 用户
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 发送消息
public void sendMessage(String message) {
StudyGroup.sendMessage(this, message);
}
}
// 中介者模式测试
public class Test {
public static void main(String[] args) {
User tom = new User("Tom");
User lucy = new User("Lucy");
tom.sendMessage("Hi Lucy! Let's learn design pattern!");
lucy.sendMessage("OK!");
}
}
// 输出
Tue Apr 02 22:04:40 CST 2019 [Tom]: Hi Lucy! Let's learn design pattern!
Tue Apr 02 22:04:40 CST 2019 [Lucy]: OK!
(2)应用
中介者 java.util.Timer,方法java.util.Timer.sched,被封装的对象:TimerTask。
9.责任链模式
为请求创建一个接受此次请求对象的链。
(1)实例
// 课程
public class Course {
private String name;
private String article;
private String video;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getArticle() {
return article;
}
public void setArticle(String article) {
this.article = article;
}
public String getVideo() {
return video;
}
public void setVideo(String video) {
this.video = video;
}
@Override
public String toString() {
return "Course{" +
"name='" + name + '\'' +
", article='" + article + '\'' +
", video='" + video + '\'' +
'}';
}
}
// 批准者
public abstract class Approver {
protected Approver next;
public void setNext(Approver next) {
this.next = next;
}
/**
* 发布课程
* @param course
*/
protected abstract void deploy(Course course);
}
// 手记检查
public class ArticleApprover extends Approver {
@Override
protected void deploy(Course course) {
if (StringUtils.isNotEmpty(course.getArticle())) {
System.out.println(course.getName() + "课程手记检查通过,批准");
if (next != null) {
next.deploy(course);
}
} else {
System.out.println(course.getName() + "课程手记检查不通过,不批准,流程结束");
}
}
}
// 视频检查
public class VideoApprover extends Approver {
@Override
protected void deploy(Course course) {
if (StringUtils.isNotEmpty(course.getVideo())) {
System.out.println(course.getName() + "课程视频检查通过,批准");
if (next != null) {
next.deploy(course);
}
} else {
System.out.println(course.getName() + "课程视频检查不通过,不批准,流程结束");
}
}
}
// 责任链模式测试
public class Test {
public static void main(String[] args) {
Approver articleApprover = new ArticleApprover();
Approver videoApprover = new VideoApprover();
Course course = new Course();
course.setName("Java设计模式精讲");
course.setArticle("Java设计模式精讲手记");
course.setVideo("Java设计模式精讲视频");
articleApprover.setNext(videoApprover);
articleApprover.deploy(course);
}
}
// 输出
Java设计模式精讲课程手记检查通过,批准
Java设计模式精讲课程视频检查通过,批准
(2)应用
javax.servlet.Filter
javax.servlet.FilterChain
10.访问者模式
封装作用于某种数据结构(如List/Set/Map等)中的各种元素的操作。可以在不改变各元素的类的前提下,定义作用于这些元素的操作。
(1)实例
// 课程
public abstract class Course {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 针对不同角色的访问者,设置不同的访问权限
* @param visitor 访问者
*/
public abstract void accept(IVisitor visitor);
}
// 付费课程
public class CodingCourse extends Course {
private int price;
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public void accept(IVisitor visitor) {
// 针对不同角色的访问者,设置不同的访问权限
visitor.visit(this);
}
}
// 免费课程
public class FreeCourse extends Course {
@Override
public void accept(IVisitor visitor) {
// 针对不同角色的访问者,设置不同的访问权限
visitor.visit(this);
}
}
// 访问者 不同的visitor,对相同的数据,产生不同的行为
public interface IVisitor {
void visit(FreeCourse freeCourse);
void visit(CodingCourse codingCourse);
}
// 访问者实现
public class Visitor implements IVisitor {
// 不同的visitor,对相同的数据,产生不同的行为
@Override
public void visit(FreeCourse freeCourse) {
System.out.println("免费课程:" + freeCourse.getName());
}
@Override
public void visit(CodingCourse codingCourse) {
System.out.println("付费课程:" + codingCourse.getName() + ", 价格:" + codingCourse.getPrice());
}
}
// 访问者模式测试
public class Test {
public static void main(String[] args) {
// 数据准备
List<Course> courseList = new ArrayList<>();
FreeCourse freeCourse = new FreeCourse();
freeCourse.setName("Spring实战");
CodingCourse codingCourse = new CodingCourse();
codingCourse.setName("Java设计模式");
codingCourse.setPrice(199);
courseList.add(freeCourse);
courseList.add(codingCourse);
// 数据操作
IVisitor visitor = new Visitor();
for (Course course : courseList) {
course.accept(visitor);
}
}
}
// 输出
免费课程:Spring实战
付费课程:Java设计模式, 价格:199
(2)应用
java.nio.file.FileVisitor
org.springframework.beans.factory.config.BeanDefinitionVisitor
11.状态模式
允许一个对象在其内部状态发生改变时,改变它的行为。不同状态,行为不同,且状态可相互转换。
实例
// 上下文,行为依赖于内部状态
public class CourseVideoContext {
private CourseVideoState courseVideoState;
public CourseVideoState getCourseVideoState() {
return courseVideoState;
}
public void setCourseVideoState(CourseVideoState courseVideoState) {
this.courseVideoState = courseVideoState;
// 重要
this.courseVideoState.setCourseVideoContext(this);
}
public static final PlayState PLAY_STATE = new PlayState();
public static final SpeedState SPEED_STATE = new SpeedState();
public static final PauseState PAUSE_STATE = new PauseState();
public static final StopState STOP_STATE = new StopState();
// 行为根据状态CourseVideoState的变化而变化
public void play() {
this.courseVideoState.play();
}
public void speed() {
this.courseVideoState.speed();
}
public void stop() {
this.courseVideoState.stop();
}
public void pause() {
this.courseVideoState.pause();
}
}
// 状态
public abstract class CourseVideoState {
protected CourseVideoContext courseVideoContext;
public void setCourseVideoContext(CourseVideoContext courseVideoContext) {
this.courseVideoContext = courseVideoContext;
}
public abstract void play();
public abstract void speed();
public abstract void pause();
public abstract void stop();
}
// 播放状态
public class PlayState extends CourseVideoState {
@Override
public void play() {
System.out.println("正常播放课程视频状态");
}
@Override
public void speed() {
super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE);
}
@Override
public void pause() {
super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE);
}
@Override
public void stop() {
super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
}
}
// 快进状态
public class SpeedState extends CourseVideoState {
@Override
public void play() {
super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
}
@Override
public void speed() {
System.out.println("快进播放课程视频状态");
}
@Override
public void pause() {
super.courseVideoContext.setCourseVideoState(CourseVideoContext.PAUSE_STATE);
}
@Override
public void stop() {
super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
}
}
// 暂停状态
public class PauseState extends CourseVideoState {
@Override
public void play() {
super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
}
@Override
public void speed() {
super.courseVideoContext.setCourseVideoState(CourseVideoContext.SPEED_STATE);
}
@Override
public void pause() {
System.out.println("暂停播放课程视频状态");
}
@Override
public void stop() {
super.courseVideoContext.setCourseVideoState(CourseVideoContext.STOP_STATE);
}
}
// 停止状态
public class StopState extends CourseVideoState {
@Override
public void play() {
super.courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
}
@Override
public void speed() {
System.out.println("ERROR! 停止状态无法快进");
}
@Override
public void pause() {
System.out.println("ERROR! 停止状态无法暂停");
}
@Override
public void stop() {
System.out.println("停止播放课程视频状态");
}
}
// 状态模式测试
public class Test {
public static void main(String[] args) {
CourseVideoContext courseVideoContext = new CourseVideoContext();
courseVideoContext.setCourseVideoState(CourseVideoContext.PLAY_STATE);
System.out.println("当前状态: " + courseVideoContext.getCourseVideoState().getClass().getSimpleName());
courseVideoContext.pause();
System.out.println("当前状态: " + courseVideoContext.getCourseVideoState().getClass().getSimpleName());
courseVideoContext.speed();
System.out.println("当前状态: " + courseVideoContext.getCourseVideoState().getClass().getSimpleName());
courseVideoContext.stop();
System.out.println("当前状态: " + courseVideoContext.getCourseVideoState().getClass().getSimpleName());
courseVideoContext.speed();
}
}
// 输出
当前状态: PlayState
当前状态: PauseState
当前状态: SpeedState
当前状态: StopState
ERROR! 停止状态无法快进
五、设计模式总结
1.创建型
重点:工厂方法模式、抽象工厂模式、建造者模式、单例模式;
一般:原型模式。
2.结构型
重点:适配器模式、装饰者模式、代理模式、外观模式、桥接模式、享元模式;
一般:组合模式。
3.行为型
重点:策略模式、责任链模式、模板方法模式、状态模式、观察者模式、命令模式;
一般:备忘录模式、迭代器模式、中介者模式、访问者模式、解释器模式。