设计模式六大原则
-
单一原则:一个类中只完成一件/类事情,那么引起当前类发现改变的原因就只有一个,如果有多个则有可能在修改某一类功能时影响到其它功能
-
开闭原则:通过扩展实体类的行为来实现新的功能,而不是修改已有代码来实现变化新的功能,避免了对原有功能的破坏
-
里氏替换原则:运行时才可确定父类的子类类型并用子类实例来替换父类实例
-
依赖倒置原则:
-
迪米特原则:一个对象应该对其它对象有最少的了解,只关注public修饰的方法
-
接口隔离原则:创建接口时应尽量细化接口的抽象方法,做到实现类继承接口后所重写的方式都是该类所需要的
常用设计模式
单例模式
/**
* 单例模式:一个类只能被实例化一次,有效避免jvm频繁回收同一个对象
*/
public class Singleton {
// 私有化构造函数,防止通过构造函数创建实例
private Singleton() {}
// 静态内部类
// 类的静态属性只会在第一次加载类的时候初始化,所以在这里JVM帮助我们保证了线程的安全性
// 利用静态内部类特点实现延迟加载,效率高
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
// 静态内部类方式在 Singleton 类被装载时并不会立即实例化,而是在调用 getInstance 方法时才会装载 SingletonInstance 类,从而完成 Singleton 的实例化
public static synchronized Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
public static void main(String[] args) {
System.out.println(Singleton.getInstance());
System.out.println(Singleton.getInstance());
}
}
提示:Spring中可以使用@Configuration和@Bean注解自定义bean并纳入容器进行管理,默认为单例模式
工厂模式【工厂方法和抽象工厂】
工厂方法模式(简单工产模式的演变):通过依赖倒置原则动态获取接口的实例对象,弥补了简单工厂模式的缺点:
(1)工厂方法只有一个抽象工厂类和一个抽象产品类
抽象工厂可以派生出多个具体工厂类,每个具体工厂类只能创建一个具体产品类
抽象产品可以派生出多个具体产品类
抽象工厂模式(工厂方法模式的演变):工厂方法模式与抽象工厂模式的区别在于:
(2)抽象工厂只有一个抽象工厂类和多个抽象产品类(产品族)
抽象工厂类可以派生出多个具体工厂类,每个具体工厂类可以创建多个具体产品类
每个抽象产品类可以派生出多个具体产品类
抽象工厂
/**
* TODO 仓库系统服务商接口,这里定义了仓库系统中所涉及到的所有接口。
* 缺点:如果一个类不是抽象类,要实现一个接口,那必须要实现该接口里面的所有方法
*/
public interface WarehouseSystemFactory {
/**
* 查询仓库列表:获取仓库的编码和id
*/
public void queryWarehouseList();
/**
* 查询仓库的运输渠道列表:获取运输渠道的编码和id
*/
public void queryWarehouseShipMethodList();
/**
* 查询仓库的商品列表:获取商品的编码和id
*/
public void queryWarehouseSkuList();
/**
* 查询库存
*/
public void queryInventory();
/**
* 创建出库单
*/
public void createOutOrder();
/**
* 查询出库单:订单的状态
*/
public void queryOutOrder();
/**
* 查询出库单的物流信息:订单的跟踪号
*/
public void queryOutOrderLogistics();
}
抽象产品(继承抽象工厂)
/**
* TODO 仓库系统服务商关于【出库单】的抽象产品类。
* 优点1:如果一个类是抽象类,要实现一个接口,那么不必实现接口里面的每一个方法,实现抽象方法与实现类的解耦
* 优点2:当某个新的仓库实例需要更多的接口来实现辅助功能时,只需要分别在"抽象工厂"和"抽象产品"中添加新的接口即可
*/
public abstract class WarehouseSystemProduct implements WarehouseSystemFactory {
/**
* 查询库存
*/
@Override
public void queryInventory() {
System.out.println("你还没有对接queryInventory接口");
}
/**
* 创建出库单
*/
@Override
public void createOutOrder() {
System.out.println("你还没有对接createOutOrder接口");
}
/**
* 查询出库单:订单的状态
*/
@Override
public void queryOutOrder() {
System.out.println("你还没有对接queryOutOrder接口");
}
/**
* 查询出库单的物流信息:订单的跟踪号
*/
@Override
public void queryOutOrderLogistics() {
System.out.println("你还没有对接queryOutOrderLogistics接口");
}
/**
* 查询仓库列表:获取仓库的编码和id
*/
@Override
public void queryWarehouseList() {
System.out.println("你还没有对接queryWarehouseList接口");
}
/**
* 查询仓库的运输渠道列表:获取运输渠道的编码和id
*/
@Override
public void queryWarehouseShopMethodList() {
System.out.println("你还没有对接queryWarehouseShopMethodList接口");
}
/**
* 查询仓库的商品列表:获取商品的编码和id
*/
@Override
public void queryWarehouseSkuList() {
System.out.println("你还没有对接queryWarehouseSkuList接口");
}
}
YeJoin仓库系统服务商
/**
* YeJoin仓库系统服务商接口 TODO 根据自身条件实现 WarehouseSystemProduct 抽象产品即可
*/
public class YeJoinFactory extends WarehouseSystemProduct {
private WarehouseSystemProduct warehouseSystemProduct;
public YeJoinFactory() {}
public YeJoinFactory(WarehouseSystemProduct warehouseSystemProduct) {
this.warehouseSystemProduct = warehouseSystemProduct;
}
/**
* 查询库存
*/
@Override
public void queryInventory() {
this.warehouseSystemProduct.queryInventory();
}
/**
* 创建出库单
*/
@Override
public void createOutOrder() {
this.warehouseSystemProduct.createOutOrder();
}
/**
* 查询出库单:订单的状态
*/
@Override
public void queryOutOrder() {
this.warehouseSystemProduct.queryOutOrder();
}
}
YeJoin下的HuaXia仓库实例产品
/**
* YeJoin仓库系统服务商下的HuaXia仓库实例
*/
public class YeJoinForHuaXiaProduct extends WarehouseSystemProduct {
/**
* 查询库存
*/
@Override
public void queryInventory() {
System.out.println("YeJoinForHuaXiaProduct queryInventory");
}
/**
* 创建出库单
*/
@Override
public void createOutOrder() {
System.out.println("YeJoinForHuaXiaProduct createOutOrder");
}
/**
* 查询出库单:订单的状态
*/
@Override
public void queryOutOrder() {
System.out.println("YeJoinForHuaXiaProduct createOutOrder");
}
}
YeJoin下的Hwc仓库实例产品
/**
* YeJoin仓库系统服务商下的Hwc仓库实例
*/
public class YeJoinForHwcProduct extends WarehouseSystemProduct {
/**
* 查询库存
*/
@Override
public void queryInventory() {
System.out.println("YeJoinForHwcProduct queryInventory");
}
/**
* 创建出库单
*/
@Override
public void createOutOrder() {
System.out.println("YeJoinForHwcProduct createOutOrder");
}
/**
* 查询出库单:订单的状态
*/
@Override
public void queryOutOrder() {
System.out.println("YeJoinForHwcProduct queryOutOrder");
}
}
调用案例
public class Run {
public static void main(String[] args) {
// 输出:YeJoinForHuaXiaProduct queryInventory
new YeJoinFactory(new YeJoinForHuaXiaProduct()).queryInventory();
// 输出:YeJoinForHwcProduct queryInventory
new YeJoinFactory(new YeJoinForHwcProduct()).queryInventory();
// 你还没有对接queryOutOrderLogistics接口
new YeJoinFactory(new YeJoinForHwcProduct()).queryOutOrderLogistics();
}
}
总结
1、仓库系统服务商可以无限横向扩展
2、每个仓库系统服务商下的仓库实例可以无限横向扩展
观察者模式
需求:创建出库单成功以后,我司erp需要操作库存和变更订单状态
/**
* 被观察者(广播):向所有订阅该广播的观察者发送消息
* 出库单创建成功后需要:修改订单状态、修改库存、添加日志等等
*/
public class CreateOutOrderObservable extends Observable {
/**
* 注册观察者
*/
public void registerObserved(Observer observer) {
this.addObserver(observer);
}
/**
* 创建出库订单成功,通知相关观察者
*/
public void createOutOrderSuccessHandle(Object object) {
// set changed = true
this.setChanged();
// callback observable objects
this.notifyObservers(object);
}
}
/**
* 观察者(订阅者):订单
*/
public class OrderObserver implements Observer {
@SneakyThrows
@Override
public void update(Observable o, Object arg) {
System.out.println(MessageFormat.format("{0} 更新订单---->", arg.toString()));
}
}
/**
* 观察者(订阅者):库存
*/
public class StockObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println(MessageFormat.format("{0} 更新库存---->", arg.toString()));
}
}
# 测试
public class DemoClient {
public static void main(String[] args) {
// 创建订单观察者
OrderObserver orderObserver = new OrderObserver();
// 创建库存观察者
StockObserver stockObserver = new StockObserver();
// 创建被观察者
CreateOutOrderObservable createOutOrderObservable = new CreateOutOrderObservable();
// 注册订单观察者
createOutOrderObservable.registerObserved(orderObserver);
// 注册库存观察者
createOutOrderObservable.registerObserved(stockObserver);
// 通知相关观察者
createOutOrderObservable.createOutOrderSuccessHandle("createOutOrder Success!");
}
}
提示:Spring框架中也有提供相关机制来实现观察者模式:pushEvent事件传播机制
代理模式
需求:默认创建出库单时没有记录相关参数,现需要记录创建出库单操作的入参、出参
public interface Demo6Service {
String createOutOrder(String orderId);
}
@Service
public class Demo6ServiceImpl implements Demo6Service {
@Override
public String createOutOrder(String orderId) {
return "orderId";
}
}
@Service
@Slf4j
public class Demo6ServiceProxyImpl implements Demo6Service {
private Demo6ServiceImpl demo6ServiceImpl;
public Demo6ServiceProxyImpl(Demo6ServiceImpl demo6ServiceImpl) {
this.demo6ServiceImpl = demo6ServiceImpl;
}
@Override
public String createOutOrder(String orderId) {
String outOrderId = demo6ServiceImpl.createOutOrder(orderId);
log.info("入参:{}", orderId);
log.info("出参:{}", outOrderId);
return outOrderId;
}
}
适配器模式
需求:大部分仓库在查询出库单详情的时候会返回订单的物流跟踪号,但极少部分仓库是没有返回的,只是单提供了查询物流跟踪号的接口,所以这里我们使用适配器模式(适配出库单详情接口来拿到物流跟踪号)
/**
* 抽象接口类
*/
public interface WareHouseService {
Map<String,String> getOutOrder(String outOrderId);
}
/**
* 抽象类(避免继承抽象接口类后过度实现接口中的所有方法)
*/
public class WareHouseAbstract implements WareHouseService {
@Override
public Map<String,String> getOutOrder(String outOrderId) {
return null;
}
}
/**
* 抽象类的具体实现类:猩猩国际仓库(查询出库订单)
*/
public class WareHouseXxgjImpl extends WareHouseAbstract {
@Override
public Map<String,String> getOutOrder(String outOrderId) {
Map<String,String> orderMap = new HashMap<>();
orderMap.put("status", "shipped");
return orderMap;
}
}
/**
* 抽象类的具体实现类的适配器类:猩猩国际仓库(适配额外的查询物流功能)
*/
public class WareHouseXxgjAdapteeImpl {
/** 查询出库单 */
public Map<String,String> getOutOrder(String outOrderId) {
// 查询订单状态
Map<String,String> orderMap = new WareHouseXxgjImpl().getOutOrder(outOrderId);
// 查询物流编码
orderMap.put("trackNo", "跟踪号");
return orderMap;
}
}
/**
* 类适配器模式:
* 目标接口:WareHouseService
* 适配器类:WareHouseXxgjAdapteeImpl
* 适配器:WareHouseXxgjAdapterImpl
*/
public class WareHouseXxgjAdapterImpl extends WareHouseXxgjAdapteeImpl implements WareHouseService {
/** 创建出库单 */
@Override
public Map<String,String> getOutOrder(String outOrderId) {
return super.getOutOrder(outOrderId);
}
}
public class ClassApader {
public static void main(String[] args) {
Map<String,String> orderMap = new WareHouseXxgjAdapterImpl().getOutOrder("xxgj");
System.out.println(JSONObject.toJSONString(orderMap));
}
}
/**
* 对象适配器模式:相比于类适配器,跟灵活
* 目标接口:WareHouseService
* 适配器类:WareHouseXxgjAdapteeImpl
* 适配器:WareHouseXxgjAdapter2Impl
*/
/**
* 接口适配器模式:
* 当一个接口中有多个抽象方法,实现该接口的类就必须实现该接口的所有方法,
* 然而并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,
* 借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系
*/
public class WareHouseXxgjAdapter2Impl extends WareHouseAbstract {
private WareHouseXxgjAdapteeImpl wareHouseXxgjAdapteeImpl;
public WareHouseXxgjAdapter2Impl(WareHouseXxgjAdapteeImpl wareHouseXxgjAdapteeImpl) {
this.wareHouseXxgjAdapteeImpl = wareHouseXxgjAdapteeImpl;
}
/** 创建出库单 */
@Override
public Map<String,String> getOutOrder(String wareHouseType) {
return this.wareHouseXxgjAdapteeImpl.getOutOrder(wareHouseType);
}
}
public class ObjectApader {
public static void main(String[] args) {
Map<String,String> orderMap = new WareHouseXxgjAdapter2Impl(
new WareHouseXxgjAdapteeImpl()).getOutOrder("xxgj");
System.out.println(JSONObject.toJSONString(orderMap));
}
}
装饰器模式
需求:随机生产数字和字母混合的字符串,规则任意编排且无序
public interface RandomService {
/** 随机生产字符串 */
String random();
}
# 抽象接口 - 实现类
@Data
public class RandomServiceImpl implements RandomService {
private String rule;
public RandomServiceImpl(String rule) {
this.rule = rule;
}
/**
* 随机生产字符串
*/
@Override
public String random() {
System.out.println(rule);
return "";
}
}
# 抽象接口 - 抽象实现类
public class RandomAbstractImpl implements RandomService {
private RandomService randomService;
private int count;
public RandomAbstractImpl(RandomService randomService, int count) {
this.randomService = randomService;
this.count = count;
}
/** 随机生产xxx字符串 */
@Override
public String random() {
return randomService.random();
}
}
# 抽象类 - 数字实现类
public class RandomNumImpl extends RandomAbstractImpl {
private int count;
public RandomNumImpl(RandomService randomService, int count) {
super(randomService, count);
this.count = count;
}
public String randomNum() {
String strTemp = "1,2,3,4,5,6,7,8,9,0";
StringBuilder strResult = new StringBuilder();
for (int i = 0; i < count; i++) {
int random = new Random().nextInt(9);
strResult.append(strTemp.split(",")[random]);
}
return strResult.toString();
}
/**
* 随机生产数字字符串
*/
@Override
public String random() {
return super.random() + randomNum();
}
}
# 抽象类 - 字符实现类
public class RandomLetterImpl extends RandomAbstractImpl {
private int count;
public RandomLetterImpl(RandomService randomService, int count) {
super(randomService, count);
this.count = count;
}
public String randomStr() {
String strTemp = "A,B,C,D,E,F,G,H,I,G,H,I,J,K,L,M,N,O,P,Q";
StringBuilder strResult = new StringBuilder();
for (int i = 0; i < count; i++) {
int random = new Random().nextInt(9);
strResult.append(strTemp.split(",")[random]);
}
return strResult.toString();
}
/**
* 随机生产字母字符串
*/
@Override
public String random() {
return super.random() + randomStr();
}
}
/**
* 装饰器模式:
* 优点:
* 动态给对象添加一些额外的职责从而实现功能的拓展,在运行时选择不同的装饰器,从而实现不同的行为;
* 比使用继承更加灵活,通过对不同的装饰类进行排列组合,创造出很多不同行为,得到功能更为强大的对象
*
* 缺点:
* 一个装饰功能对应一个小对象,增加了系统的复杂性
*/
public static void main(String[] args) {
RandomAbstractImpl randomAbstractImpl1 = new RandomNumImpl(
new RandomLetterImpl(
new RandomServiceImpl("生产规则:3个数字字符串+2个字母字符串"), 3), 2);
System.out.println(randomAbstractImpl1.random());
RandomAbstractImpl randomAbstractImpl2 = new RandomLetterImpl(
new RandomNumImpl(
new RandomServiceImpl("生产规则:3个字母字符串 + 2个数字字符串"), 3), 2);
System.out.println(randomAbstractImpl2.random());
}