特点分类
工厂模式
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
public class ConcreteCreator extends Creator {
@Override
public <T extends Product> T createProduct(Class<T> c) {
Product product = null;
try {
product = (Product) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
// TODO: handle exception
}
return (T) product;
}
}
抽象工厂
为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类。
public abstract class AbstractFactory {
//创建A产品家族
public abstract AbstractProductA createProductA();
//创建B产品家族
public abstract AbstractProductB createProductB();
}
单例模式
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
//类中其他方法,尽量使static
public static void dosomething() {
}
}
建造者模式
应用实例
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
public abstract class Builder {
public abstract void BuildPartA(); //产品的A部件
public abstract void BuildPartB(); //产品的B部件
public abstract Product getResult(); //获取产品建造后结果
}
原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
public class Prototype implements Cloneable {
@Override
public Prototype clone() {
Prototype prototype = null;
try {
prototype = (Prototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return prototype;
}
}
深拷贝:对私有的类变量进行独立的拷贝
如:thing.arrayList = (ArrayList)this.arrayList.clone();
适配器模式
通过引入适配器,可以复用现有的类,而不需要修改源代码,将目标类和适配者解耦合,解决了接口和复用环境不一致的情况
将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
public class Adapter extends Target {
private Adaptee adaptee = new Adaptee();
@Override
public void request() {
adaptee.specificRequest();
}
}
桥接模式
抽象和实现分离。桥梁模式完全是为了解决继承的缺点而提出的设计模式
优秀的扩展能力
实现细节对客户透明。客户不用关心细节的实现,它已经由抽象层通过聚合关系完成了封装
将抽象和实现解耦,使得两者可以独立地变化。
组合模式
将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
public class Composite extends Component {
//构件容器
private ArrayList<Component> componentArrayList = new ArrayList<Component>();
//增加一个叶子构件或树枝构件
@Override
public void add(Component component) {
this.componentArrayList.add(component);
}
//删除一个叶子构件或树枝构件
@Override
public void remove(Component component) {
this.componentArrayList.remove(component);
}
//获得分支下的所有叶子构件和树枝构件
public ArrayList<Component> getChildren() {
return this.componentArrayList;
}
}
装饰模式
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
public abstract class Decorator extends Component {
private Component component = null;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
if (component != null) {
this.component.operation();
}
}
}
模版模式
定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
代理模式
为其他对象提供一种代理以控制对这个对象的访问。
public class Proxy extends Subject {
private RealSubject realSubject = null;
public Proxy() {
this.realSubject = new RealSubject();
}
@Override
public void request() {
this.before();
this.realSubject.request();
this.after();
}
//预处理
private void before() {
System.out.println("-------before------");
}
//善后处理
private void after() {
System.out.println("-------after-------");
}
}
中介者模式
用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
public abstract class Mediator {
//定义同事类
protected ConcreteColleague1 c1;
protected ConcreteColleague2 c2;
//通过 getter/setter 方法把同事类注入进来
public ConcreteColleague1 getC1() {
return c1;
}
public void setC1(ConcreteColleague1 c1) {
this.c1 = c1;
}
public ConcreteColleague2 getC2() {
return c2;
}
public void setC2(ConcreteColleague2 c2) {
this.c2 = c2;
}
//中介者模式的业务逻辑
public abstract void doSomething1();
public abstract void doSomething2();
}
命令模式
将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
责任链模式
使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
public abstract class Handler {
private Handler nextHandler; //下一个处理者
public final Response handlerMessage(Request request) {
Response response = null;
if (this.getHandlerLevel().equals(request.getRequestLevel())) { //判断是否是自己的处理级别
response = this.echo(request);
} else {
if (this.nextHandler != null) { //下一处理者不为空
response = this.nextHandler.handlerMessage(request);
} else {
//没有适当的处理者,业务自行处理
}
}
return response;
}
//设定下一个处理者
public void setNext(Handler handler) {
this.nextHandler = handler;
}
//每个处理者的处理等级
protected abstract Level getHandlerLevel();
//每个处理者都必须实现的处理任务
protected abstract Response echo(Request request);
}
迭代器模式
它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。
观察者模式
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
public class Subject {
//观察者数组
private Vector<Observer> oVector = new Vector<>();
//增加一个观察者
public void addObserver(Observer observer) {
this.oVector.add(observer);
}
//删除一个观察者
public void deleteObserver(Observer observer) {
this.oVector.remove(observer);
}
//通知所有观察者
public void notifyObserver() {
for (Observer observer : this.oVector) {
observer.update();
}
}
}
外观模式
要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。
public class Facade {
//被委托的对象
SubSystemA a;
SubSystemB b;
SubSystemC c;
SubSystemD d;
public Facade() {
a = new SubSystemA();
b = new SubSystemB();
c = new SubSystemC();
d = new SubSystemD();
}
//提供给外部访问的方法
public void methodA() {
this.a.dosomethingA();
}
public void methodB() {
this.b.dosomethingB();
}
public void methodC() {
this.c.dosomethingC();
}
public void methodD() {
this.d.dosomethingD();
}
}
备忘录模式
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
public class Originator {
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public Memento createMento() {
return (new Memento(state));
}
public void setMemento(Memento memento) {
state = memento.getState();
}
public void show() {
System.out.println("state = " + state);
}
}
访问者模式
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
解释器模式
给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
享元模式
使用共享对象可有效地支持大量的细粒度的对象。
public class FlyweightFactory {
//定义一个池容器
private static HashMap<String, Flyweight> pool = new HashMap<>();
//享元工厂
public static Flyweight getFlyweight(String extrinsic) {
Flyweight flyweight = null;
if (pool.containsKey(extrinsic)) { //池中有该对象
flyweight = pool.get(extrinsic);
System.out.print("已有 " + extrinsic + " 直接从池中取---->");
} else {
//根据外部状态创建享元对象
flyweight = new ConcreteFlyweight(extrinsic);
//放入池中
pool.put(extrinsic, flyweight);
System.out.print("创建 " + extrinsic + " 并从池中取出---->");
}
return flyweight;
}
}
使用if else,多级嵌套走不同的分支,代码耦合性太强,导致修改起来很麻烦
策略模式
定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。
- 优点
1、算法可以自由切换。
2、 避免使用多重条件判断。
3、扩展性良好。
- 缺点
1、策略类会增多。
2、所有策略类都需要对外暴露。
- 使用场景
1、许多类之间的区别仅在于它们的行为,动态地让一个对象在许多行为中选择一种行为。
2、动态地在几种算法中选择一种。
3、如果不用恰当的模式,行为就只好使用多重的条件选择语句来实现。
- 注意事项
如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
订单实体类
@Data
public class Order {
/**
* 订单来源
*/
private String source;
/**
* 支付方式
*/
private String payMethod;
/**
* 订单编号
*/
private String code;
/**
* 订单金额
*/
private BigDecimal amount;
// ...其他的一些字段
}
订单服务类
/**
* 订单服务
*
* @author Moses
* @date 2020/12/18
*/
@Service
public class OrderService {
private Map<OrderHandlerType, OrderHandler> orderHandleMap;
/**
* 选择OrderHandlerType作为map的key值
* 参数v -> v表示选择将原来的对象作为map的value值
* 参数(v1, v2) -> v1中,如果v1与v2的key值相同,选择v1作为那个key所对应的value值
*
* @param orderHandlers 订单处理程序
*/
@Autowired
public void setOrderHandleMap(List<OrderHandler> orderHandlers) {
// 注入各种类型的订单处理类
orderHandleMap = orderHandlers.stream()
.peek(orderHandler -> System.out.println(AnnotationUtils.findAnnotation(orderHandler.getClass(), OrderHandlerType.class)))
.peek(System.out::println).collect(
Collectors.toMap(orderHandler -> AnnotationUtils.findAnnotation(orderHandler.getClass(), OrderHandlerType.class),
v -> v, (v1, v2) -> v1));
}
public void orderService(Order order) {
// ...一些前置处理
// 通过订单来源确以及支付方式获取对应的handler
OrderHandlerType orderHandlerType = new OrderHandlerTypeImpl(order.getSource(), order.getPayMethod());
OrderHandler orderHandler = orderHandleMap.get(orderHandlerType);
orderHandler.handle(order);
// ...一些后置处理
}
}
订单处理类
public interface OrderHandler {
void handle(Order order);
}
实现类
@OrderHandlerType(source = "mobile", payMethod = "aliPay")
public class MobileAliPayOrderHandler implements OrderHandler {
@Override
public void handle(Order order) {
System.out.println("支付宝处理移动端订单");
}
}
@OrderHandlerType(source = "mobile", payMethod = "weChat")
public class MobileWeChatOrderHandler implements OrderHandler {
@Override
public void handle(Order order) {
System.out.println("微信处理移动端订单");
}
}
@OrderHandlerType(source = "pc", payMethod = "aliPay")
public class PCAliPayOrderHandler implements OrderHandler {
@Override
public void handle(Order order) {
System.out.println("支付宝处理PC端订单");
}
}
@OrderHandlerType(source = "pc", payMethod = "weChat")
public class PCWeChatOrderHandler implements OrderHandler {
@Override
public void handle(Order order) {
System.out.println("微信处理PC端订单");
}
}
订单类型
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
public @interface OrderHandlerType {
String source();
String payMethod();
}
实现类
public class OrderHandlerTypeImpl implements OrderHandlerType {
private String source;
private String payMethod;
public OrderHandlerTypeImpl(String source, String payMethod) {
this.source = source;
this.payMethod = payMethod;
}
@Override
public String source() {
return source;
}
@Override
public String payMethod() {
return payMethod;
}
@Override
public Class<? extends Annotation> annotationType() {
return OrderHandlerType.class;
}
@Override
public int hashCode() {
int hashCode = 0;
hashCode += (127 * "source".hashCode()) ^ source.hashCode();
hashCode += (127 * "payMethod".hashCode()) ^ payMethod.hashCode();
return hashCode;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof OrderHandlerType)) {
return false;
}
OrderHandlerType other = (OrderHandlerType) obj;
return source.equals(other.source()) && payMethod.equals(other.payMethod());
}
}
测试
@RunWith(SpringRunner.class)
@ComponentScan(basePackages = {"com.moses.framework.tools.patterns"})
@SpringBootTest(classes = StrategyTest.class)
public class StrategyTest {
@Autowired
OrderService orderService;
@Test
public void strategy() {
Order order = new Order();
order.setSource("pc");
order.setPayMethod("weChat");
orderService.orderService(order);
}
}
这样以来,不管以后业务怎么发展,OrderService核心逻辑不会改变,只需要扩展OrderHandler即可。
状态模式
当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。
优点:
1、封装了转换规则。
2、枚举可能的状态,在枚举状态之前需要确定状态种类。
3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点:
1、状态模式的使用必然会增加系统类和对象的个数。
2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
使用场景:
1、行为随状态改变而改变的场景。
2、条件、分支语句的代替者。
注意事项:
在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。
状态接口
public interface State {
public void doAction(Context context);
}
实现类
public class StartState implements State {
@Override
public void doAction(Context context) {
System.out.println("Player is in start state");
context.setState(this);
}
@Override
public String toString() {
return "Start State";
}
}
public class StopState implements State {
@Override
public void doAction(Context context) {
System.out.println("Player is in stop state");
context.setState(this);
}
@Override
public String toString() {
return "Stop State";
}
}
Context
@Setter
@Getter
public class Context {
private State state;
public Context() {
state = null;
}
}
测试
public class StatePatternDemo {
public static void main(String[] args) {
Context context = new Context();
StartState startState = new StartState();
startState.doAction(context);
System.out.println(context.getState().toString());
StopState stopState = new StopState();
stopState.doAction(context);
System.out.println(context.getState().toString());
}
}
strategy pattern & state pattern
相同点
两者通过将行为和状态拆分成一系列小的组件,由条件和状态进行功能更替,这样符合开闭原则,便于扩展。
此外均可作为if else或者分支的替换方案;
支持的最大行为和状态均有限;
不同点
策略模式中,类的功能是根据当前条件主动更改;
状态模式中,类的功能是被动由当前状态更改;
策略模式中每个行为或算法之间没有关联;
状态模式中的状态之间有关联,并且状态本身控制着状态转移;
单例模式
静态类
public class Singleton_00 {
public static Map<String, String> cache = new ConcurrentHashMap<String, String>();
}
懒汉模式(线程不安全)
public class Singleton_01 {
private static Singleton_01 instance;
private Singleton_01() {
}
public static Singleton_01 getInstance() {
if (null != instance) return instance;
return new Singleton_01();
}
}
有多个访问者同时去获取对象实例,就会造成多个同样的实例并存
懒汉模式(线程安全)
public class Singleton_02 {
private static Singleton_02 instance;
private Singleton_02() {
}
public static synchronized Singleton_02 getInstance() {
if (null != instance) return instance;
return new Singleton_02();
}
}
所有的访问都因需要锁占⽤导致资源的浪费
饿汉模式(线程安全)
public class Singleton_03 {
private static Singleton_03 instance = new Singleton_03();
private Singleton_03() {
}
public static Singleton_03 getInstance() {
return instance;
}
}
⽆论你程序中是否⽤到这样的类都会在程序启动之初进⾏创
建
使⽤类的内部类(线程安全)
public class Singleton_04 {
private static class SingletonHolder {
private static Singleton_04 instance = new Singleton_04();
}
private Singleton_04() {
}
public static Singleton_04 getInstance() {
return SingletonHolder.instance;
}
}
既保证了线程安全有保证了懒加载,同时不会因为加锁的⽅
式耗费性能。
双重锁校验(线程安全)
public class Singleton_05 {
private static volatile Singleton_05 instance;
private Singleton_05() {
}
public static Singleton_05 getInstance() {
if (null != instance) return instance;
synchronized (Singleton_05.class) {
if (null == instance) {
instance = new Singleton_05();
}
}
return instance;
}
}
枚举单例(线程安全)
public enum Singleton_07 {
INSTANCE;
public void test() {
System.out.println("hi~");
}
}
Effective Java 作者推荐使⽤枚举的⽅式解决单例模式
线程安全、⾃由串⾏化、单⼀实例
调用方式
@Test
public void test() {
Singleton_07.INSTANCE.test();