课堂内容
学习代码:https://github.com/CNXMBuyu/design-pattern-study.git
简单工厂
package cn.hgy.simplefactory;
/**
* @author guoyu.huang
* @version 1.0.0
*/
public class SimpleFactory {
public BaseClass getClass(String type) {
String classAType = "classA";
if (classAType.equals(type)) {
return new ClassA();
} else {
return new ClassB();
}
}
}
如果要增加类型,需要更新工厂代码,不符合开闭原则。解决方案如下:
工厂模式
工厂接口
package cn.hgy.factory;
/**
* @author guoyu.huang
* @version 1.0.0
*/
public abstract class BaseFactory {
protected abstract boolean handle(String type);
public abstract BaseClass create();
}
工厂接口实现
package cn.hgy.factory;
/**
* @author guoyu.huang
* @version 1.0.0
*/
public class ClassAFactory extends BaseFactory {
private static final String CLASS_A_TYPE = "classA";
@Override
public boolean handle(String type) {
return CLASS_A_TYPE.equals(type);
}
@Override
public BaseClass create() {
return new ClassA();
}
}
工厂类
package cn.hgy.factory;
import java.io.File;
import java.util.*;
/**
* @author guoyu.huang
* @version 1.0.0
*/
public class Factory {
public BaseClass getClass(String type) {
List<BaseFactory> factoryList = getAllClass();
for(BaseFactory baseFactory : factoryList) {
if(baseFactory.handle(type)){
return baseFactory.create();
}
}
return null;
}
/**
* 根据反射获取所有的工厂类
* @return
*/
private List<BaseFactory> getAllClass(){
File directory = new File("D:\\codespace\\design-pattern-study\\factory\\target\\classes\\cn\\hgy\\factory");
File[] files = directory.listFiles();
List<BaseFactory> factoryList = new ArrayList<>();
for (File file : files) {
String filePath = file.getPath().replace("D:\\codespace\\design-pattern-study\\factory\\target\\classes\\", "");
filePath = filePath.replaceAll(".class", "");
filePath = filePath.replaceAll("\\\\", ".");
try {
Class clazz = Class.forName(filePath);
if(clazz.getSuperclass() != null && clazz.getSuperclass().equals(BaseFactory.class)){
BaseFactory factory = (BaseFactory)Class.forName(filePath).newInstance();
factoryList.add(factory);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return factoryList;
}
}
如果使用spring,做法则更简单,代码如下:
@Component
public class ClassAFactory extends BaseFactory {
// something
}
/**
* @author guoyu.huang
* @version 1.0.0
*/
@Component
public class Factory {
@Autowired
private List<BaseFactory> factoryList;
public BaseClass getClass(String type) {
for(BaseFactory baseFactory : factoryList) {
if(baseFactory.handle(type)){
return baseFactory.create();
}
}
return null;
}
}
使用工厂实现简单spring工厂,参考地址:https://github.com/CNXMBuyu/design-pattern-study.git
单例模式
饿汉式
package cn.hgy.single.eager;
/**
* 饿汉单例模式,先实例化
*
* @author guoyu.huang
* @version 1.0.0
*/
public class EagerSingleton {
private static EagerSingleton eagerSingleton = new EagerSingleton();
private EagerSingleton(){
}
public static EagerSingleton getInstance(){
return eagerSingleton;
}
}
懒汉式
package cn.hgy.single.lazy;
/**
* 懒汉单例模式,需要的时候实例化
*
* @author guoyu.huang
* @version 1.0.0
*/
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
return new LazySingleton();
} else {
return instance;
}
}
}
双重校验
package cn.hgy.single.doublecheck;
/**
* 双重校验单例模式
*
* @author guoyu.huang
* @version 1.0.0
*/
public class DoubleCheckSingleton {
private static volatile DoubleCheckSingleton instance;
private DoubleCheckSingleton() {
}
public static DoubleCheckSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckSingleton.class) {
if(instance == null){
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}
内部类
效果等同于双重校验
package cn.hgy.single.inner;
import cn.hgy.single.doublecheck.DoubleCheckSingleton;
/**
* @author guoyu.huang
* @version 1.0.0
*/
public class InnerSingleton {
private InnerSingleton(){}
public static InnerSingleton getInstance() {
return Singleton.instance;
}
private static class Singleton{
private static final InnerSingleton instance = new InnerSingleton();
}
}
适配器模式
适配器模式是为了原本由于接口不兼容而不能一起工作的类可以一起工作。
通用代码-基础类
public interface OldInterface {
void invoke(OldParameter parameter);
}
public class OldInterfaceImpl implements OldInterface{
@Override
public void invoke(OldParameter parameter) {
System.out.println(parameter.toString());
}
}
public class OldParameter {
private String a;
private String b;
// 省略get和set
}
public interface NewInterface {
void invoke(NewParameter parameter);
}
public class NewParameter {
private String newA;
private String newB;
// 省略get和set
}
类适配器
当新接口和老接口提供的函数大部分相同时,可以使用类适配器来提高代码的复用率。否则建议使用对象适配器,避免接口暴露太多不可用的接口,降低接口的易用性。
public class ClassAdapter extends OldInterfaceImpl implements NewInterface{
@Override
public void invoke(NewParameter parameter) {
OldParameter oldParameter = new OldParameter();
oldParameter.setA(parameter.getNewA());
oldParameter.setB(parameter.getNewB());
super.invoke(oldParameter);
}
}
对象适配器
只暴露合适的接口,再通过组合的方式来提高代码的复用率。
public class ObjectAdapter implements NewInterface{
private OldInterface oldInterface = new OldInterfaceImpl();
@Override
public void invoke(NewParameter parameter) {
OldParameter oldParameter = new OldParameter();
oldParameter.setA(parameter.getNewA());
oldParameter.setB(parameter.getNewB());
oldInterface.invoke(oldParameter);
}
}
通用代码-调用类
public class Main {
public static void main(String[] args) {
NewParameter parameter = new NewParameter();
parameter.setNewA("a");
parameter.setNewB("b");
new ClassAdapter().invoke(parameter);
new ObjectAdapter().invoke(parameter);
}
}
模板模式
什么是模板模式
将算法整体架构定义好,让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。
为什么使用模板模式
代码复用
如何使用模板模式
定义算法整体架构(抽象类),将需要子类来实现的方法定义为抽象方法。
public abstract class Player {
public void initPlayer() {
// 保存玩家信息
savePlayer();
// 初始化玩家数据,因为每款游戏都不同,所以需要有子类具体实现
initData();
}
protected void savePlayer() {
System.out.println("已保存玩家信息");
}
/**
* 初始化玩家数据
*/
protected abstract void initData();
}
public class GamePlayer extends Player {
@Override
protected void initData() {
System.out.println("初始化游戏玩家");
}
}
相似功能:回调
A类事先注册某个函数F到B类,A类在调用B类的P函数的时候,B类反过来调用A类注册给它的F函数。
public class Player {
public void initPlayer(PlayerCallback playerCallback){
// 保存玩家信息
savePlayer();
// 初始化玩家数据,因为每款游戏都不同,所以需要有子类具体实现
playerCallback.initData();
}
protected void savePlayer(){
System.out.println("已保存玩家信息");
}
}
public interface PlayerCallback {
/**
* 初始化玩家数据
*/
void initData();
}
// 调用类
public class Main {
public static void main(String[] args) {
Player player = new Player();
player.initPlayer(new PlayerCallback() {
@Override
public void initData() {
System.out.println("初始化游戏玩家数据");
}
});
}
}
回调函数的经典案例:spring的JdbcTemplate
模板模板是使用继承来实现,而回调函数是使用组合来实现。
组合模式
装饰者模式
装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。它主要的作用是给原始类添加增强功能。
通用代码-基础类
public interface IBusinessService {
void invoke();
void invoke2();
}
public class BusinessService implements IBusinessService{
public void invoke(){
System.out.println("invoke");
}
public void invoke2() {
System.out.println("invoke2");
}
}
现在需要对invoke函数增加记录操作的功能。
装饰器思路
继承相同接口,将原始类当作参数传入,增强功能。
public class OperationService implements IBusinessService {
private IBusinessService businessService;
// 这里通过构造函数参数
public OperationService(IBusinessService businessService) {
this.businessService = businessService;
}
@Override
public void invoke() {
businessService.invoke();
// 增强功能
System.out.println("operation");
}
@Override
public void invoke2() {
businessService.invoke2();
}
}
通用代码-调用类
public class Main {
public static void main(String[] args) {
IBusinessService businessService = new BusinessService();
// 注意,这里传入的实参
IBusinessService operationService = new OperationService(businessService);
operationService.invoke();
}
}
延申阅读
spring中的设计模式
控制反转
Service依赖Repository,原先是在Service中实例化Repository,现在将实例化的动作放在容器中实现。
单例模式
SpringMVC
分布式事务
- 事务补偿机制和回滚