代码demo:https://github.com/morebetter1/DesignPatternDemos
目录
主要使用的几种模式
抽象类
抽象方法是一种特殊的方法:它只有声明,而没有具体的实现,抽象方法必须用abstract关键字进行修饰。如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。同时抽象类中可以不含抽象方法。简言之:含抽象方法的类一定是抽象类,抽象类不一定含有抽象方法。
抽象类特点:1、abstrac 声明的类,不能被实例化。 2、抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。 3、如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类
抽象类的意义:所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类,抽象类就是为了继承而存在的,抽象类中的抽象方法是根据子类的实际需求来进行不同的实现的。
接口
1、在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。2、接口是一种极度抽象的类型,它比抽象类更加“抽象”,并且一般情况下不在接口中定义变量。3、普通类遵循接口必须实现接口中所有的方法,抽象类遵循接口可以不用实现接口中的方法
抽象类和接口的联系
抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。
组合/聚合复用原则又叫合成复用原则
尽量使用对象组合,而不是继承来达到复用的目的 合成(Composition,也有翻译成组合)和聚合(Aggregation),都是关联的特殊种类。聚合表示一种弱的“拥有”关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分;合成(组合)是一种强的“拥有”关系,体现了严格的部分与整体的关系,部分和整体的生命周期是一样的
类之间的关系:
六种关系的耦合度大小是:泛化(继承) = 实现 > 组合 > 聚合 > 关联 > 依赖
记图技巧:实现表示强关系,虚线表示弱关系。空心菱形,代表空器皿里可以放很多相同的东西,聚集在一起。实心菱形,代表器皿里已经有实体结构的存在,生死与共组合关系。
- 泛化(继承)is-a:B类继承A类。 图形:实线和空心箭头组成
- 实现 is-a:B类实现A接口。图形:虚线和空心箭头
- 组合(合成)contains-a:A是B类的成员属性,是B类的一部分,是部分和整体的关系。组合表示一种强的“拥有”关系,A脱离B无法独立存在(如:头和嘴的关系,没有了头,嘴也就不存在了)。图形:实线和实心菱形
- 聚合 has-a:B类包含A类,但A类不是B类的一部分,聚合表示一种弱的“拥有”关系,A可以脱离B单独存在。(如:学校与老师的关系,学校包含老师,但如果学校停办了,老师依然存在)。图形:实线和空心菱形
- 关联 contains/has-a:组合和聚合都属于关联,简单讲A类和B类有某种“拥有”联系。图形:实线和箭头
- 依赖 use-a:是一种使用关系,互相合作(方法中用到,类中用到,类的成员属性,方法中的参数类型,方法中的返回类型等各种关系都可以说成依赖……)。图形:虚线和箭头
7大设计原则:
(来自:一句话总结软件设计七大原则 Java设计模式:23种设计模式全面解析(超级详细) )
设计原则 | 一句话归纳 | 目的 |
---|---|---|
开闭原则 | 对扩展开放,对修改关闭 | 降低维护带来的新风险 |
依赖倒置原则 | 高层不应该依赖低层,要面向接口编程 | 更利于代码结构的升级扩展 |
单一职责原则 | 一个类只干一件事,实现类要单一 | 便于理解,提高代码的可读性 |
接口隔离原则 | 一个接口只干一件事,接口要精简单一 | 功能解耦,高聚合、低耦合 |
迪米特法则 | 不该知道的不要知道,一个类应该保持对其它对象最少的了解,降低耦合度 | 只和朋友交流,不和陌生人说话,减少代码臃肿 |
里氏替换原则 | 不要破坏继承体系,子类重写方法功能发生改变,不应该影响父类方法的含义 | 防止继承泛滥 |
合成复用原则 | 尽量使用组合或者聚合关系实现代码复用,少使用继承 | 降低代码耦合 |
23种设计模式:
(来自:设计模式简介 | 菜鸟教程, Java设计模式:23种设计模式全面解析(超级详细))
序号 | 模式 & 描述 | 包括 |
---|---|---|
1 | 创建型模式 | 单例模式(Singleton Pattern) 工厂模式(Factory Pattern) 抽象工厂模式(Abstract Factory Pattern) 某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。 建造者模式(Builder Pattern) 原型模式(Prototype Pattern) |
2 | 结构型模式 这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。 | 适配器模式(Adapter Pattern) 桥接模式(Bridge Pattern) 过滤器模式(Filter、Criteria Pattern) 组合模式(Composite Pattern) 装饰器模式(Decorator Pattern) 外观模式(Facade Pattern) 享元模式(Flyweight Pattern) 代理模式(Proxy Pattern) |
3 | 行为型模式 这些设计模式特别关注对象之间的通信。 | 责任链模式(Chain of Responsibility Pattern) 命令模式(Command Pattern) 解释器模式(Interpreter Pattern) 迭代器模式(Iterator Pattern) 中介者模式(Mediator Pattern) 备忘录模式(Memento Pattern) 观察者模式(Observer Pattern) 状态模式(State Pattern) 空对象模式(Null Object Pattern) 策略模式(Strategy Pattern) 模板模式(Template Pattern) 访问者模式(Visitor Pattern) |
4 | J2EE 模式 这些设计模式特别关注表示层。这些模式是由 Sun Java Center 鉴定的。 | MVC 模式(MVC Pattern) 业务代表模式(Business Delegate Pattern) 组合实体模式(Composite Entity Pattern) 数据访问对象模式(Data Access Object Pattern) 前端控制器模式(Front Controller Pattern) 拦截过滤器模式(Intercepting Filter Pattern) 服务定位器模式(Service Locator Pattern) 传输对象模式(Transfer Object Pattern) |
创造型模式
单例模式,工厂模式,静态工厂模式,原型模式,建造者模式
单例模式
package create;
/**
* 创建型模式-单例模式
*/
public class Singleton {
public static void main(String[] args) {
SingleType1 type1Instance1 = SingleType1.getInstance();
SingleType1 type1Instance2 = SingleType1.getInstance();
System.out.println(type1Instance1 == type1Instance2); // true
System.out.println("type1Instance1.hashCode=" + type1Instance1.hashCode());
System.out.println("type1Instance2.hashCode=" + type1Instance2.hashCode());
SingleType2 type2Instance1 = SingleType2.getInstance();
SingleType2 type2Instance2 = SingleType2.getInstance();
System.out.println(type2Instance1 == type2Instance2); // true
System.out.println("type2Instance1.hashCode=" + type2Instance1.hashCode());
System.out.println("type2Instance2.hashCode=" + type2Instance2.hashCode());
SingleType3 type3Instance1 = SingleType3.getInstance();
SingleType3 type3Instance2 = SingleType3.getInstance();
System.out.println(type3Instance1 == type3Instance2); // true
System.out.println("type3Instance1.hashCode=" + type3Instance1.hashCode());
System.out.println("type3Instance2.hashCode=" + type3Instance2.hashCode());
SingleType4 type4Instance1 = SingleType4.INSTANCE;
SingleType4 type4Instance2 = SingleType4.INSTANCE;
System.out.println(type4Instance1 == type4Instance2); // true
System.out.println("type4Instance1.hashCode=" + type4Instance1.hashCode());
System.out.println("type4Instance2.hashCode=" + type4Instance2.hashCode());
}
}
//饿汉式
class SingleType1{
//内部创建实例
private static final SingleType1 instance = new SingleType1();
//构造器私有制,外部不能实例化此类
private SingleType1(){
}
//共有方法返回实例
public static SingleType1 getInstance(){
return instance;
}
}
//饿汉式
class SingleType11{
private static final SingleType11 instance ;
static {
instance = new SingleType11();
}
//构造器私有制,外部不能实例化此类
private SingleType11(){
}
public static SingleType11 getInstance(){
return instance;
}
}
//懒汉式
//在多线程下,如果去掉关键字 volatile 和 synchronized,则存在线程非安全的问题,一个线程进入了 if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。如果不删除这两个关键字就能保证线程安全,但是每次访问时都要同步,会影响性能,且消耗更多的资源,这是懒汉式单例的缺点
class SingleType2{
private SingleType2(){}
//volatile 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。(实现可见性),轻量级synchronized
//volatile用来保证instance可见性的,在所有线程中同步,共享,可见
//volatile保证了线程间的可见性,和一定程度上的顺序性(不能保证原子性),更好的方式是用一个boolean变量标识对象是否创建过(原子性)
//volatile 通俗说 就是多线程时一个线程修改了 volatile修饰的变量时 别的线程能立马就读到这个新值
private static volatile SingleType2 instance = null; //volatile 保证 instance 在所有线程中同步
//synchronized 线程锁,避免多线程不安全
public static synchronized SingleType2 getInstance(){
if(instance == null){
instance = new SingleType2();
}
return instance;
}
}
// 静态内部类完成, 相较上一种方式更推荐使用这种方式
class SingleType3{
private SingleType3(){}
private static class SingleInstance{
private static final SingleType3 INSTANCE = new SingleType3();
}
public static SingleType3 getInstance(){
return SingleType3.SingleInstance.INSTANCE;
}
}
//使用枚举,可以实现单例, 推荐使用
//这借助 JDK1.5 中添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,更是 Effective Java 作者 Josh Bloch 提倡的方式
enum SingleType4 {
INSTANCE; //属性
public void sayOK() {
System.out.println("ok~");
}
}
单例模式小结:
- 说明:单例模式是设计模式中最简单的模式之一,将类的构造函数设为私有的,外部类就无法调用该构造函数,也就无法生成多个实例。这时该类自身必须定义一个静态私有实例,并向外提供一个静态的公有函数用于创建或获取该静态私有实例。单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能,当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用 new。
- 结构:类的构造函数为私有的,自身必须定义一个静态私有实例,并向外提供一个静态的公有函数用于创建或获取该静态私有实例。
- 源码分析 JDK中,java.lang.Runtime就是经典的单例模式(饿汉式)
- 使用场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session 工厂等)
- 优点:单例模式可以保证内存里只有一个实例,减少了内存的开销节省资源。设置全局访问点,可以优化和共享资源的访问。
- 缺点:单例模式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。
工厂模式:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。由简到繁分三种简单工厂模式、工厂方法模式和抽象工厂模式,
工厂模式---要创建的产品不多,只要一个工厂类就可以完成,创建实例的方法通常为静态(static)方法,因此简单工厂模式(Simple Factory Pattern)又叫作静态工厂方法模式(Static Factory Method Pattern)。每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
public class Client {
public static void main(String[] args) {
}
//抽象产品
public interface Product {
void show();
}
//具体产品:ProductA
static class ConcreteProduct1 implements Product {
public void show() {
System.out.println("具体产品1显示...");
}
}
//具体产品:ProductB
static class ConcreteProduct2 implements Product {
public void show() {
System.out.println("具体产品2显示...");
}
}
final class Const {
static final int PRODUCT_A = 0;
static final int PRODUCT_B = 1;
static final int PRODUCT_C = 2;
}
static class SimpleFactory {
public static Product makeProduct(int kind) {
switch (kind) {
case Const.PRODUCT_A:
return new ConcreteProduct1();
case Const.PRODUCT_B:
return new ConcreteProduct2();
}
return null;
}
}
}
简单工厂模式小结:
- 结构:简单工厂类,负责实现创建所有产品。抽象产品类,产品的父类接口。具体产品类工厂类创建的对象。
- 使用场景:
- 优点:
- 缺点:每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
工厂模式
抽象工厂模式
---对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则
主要角色如下。
- 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
- 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
建造者模式 (构建者模式)
主要角色如下: 主要将对象和部件分开创建, 最后组装到一起产生一个复杂对象的过程,同样的构建过程因为具体部件的不同可以创建不同的复杂对象。product定义对象,builder和concrete创建组件,director组装产生一个复杂对象product
- 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。
- 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。
- 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
- 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。
实例1 共享单车实例:单车产品类包含:车胎和车座等零件。抽象构建类包含:创建车胎,创建车座,最后创建单车对象。具体构建类A(ofo单车构建类)包含:创建车胎a,创建车座a,最后创建ofo单车。具体构建类B(Mobike单车构建类)包含:创建车胎b,创建车座b,最后创建Mobike单车。指挥者类包括:builder对象属性(输入builder)和产品构建方法(输出产品)这个方法的职能就是用builder创建。一篇文章就彻底弄懂建造者模式(Builder Pattern) - 简书
//产品角色
class Product {
private String partA;
private String partB;
private String partC;
public void setPartA(String partA) {
this.partA = partA;
}
public void setPartB(String partB) {
this.partB = partB;
}
public void setPartC(String partC) {
this.partC = partC;
}
public void show() {
//显示产品的特性
}
}
//抽象建造者
abstract class Builder {
//创建产品对象
protected Product product = new Product();
public abstract void buildPartA();
public abstract void buildPartB();
public abstract void buildPartC();
//返回产品对象
public Product getResult() {
return product;
}
}
//具体建造者
public class ConcreteBuilder extends Builder {
public void buildPartA() {
product.setPartA("建造 PartA");
}
public void buildPartB() {
product.setPartB("建造 PartB");
}
public void buildPartC() {
product.setPartC("建造 PartC");
}
}
//指挥者
class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
//产品构建与组装方法
public Product construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getResult();
}
}
//客户调用
public class Client {
public static void main(String[] args) {
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
Product product = director.construct();
product.show();
}
}
原型模式:
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象
结构:原型类 实现cloneable接口clone方法的类,只有实现了clone方法才可以被克隆。
- 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
- 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。可通过序列化实现深克隆。
package create;
import java.io.*;
/**
* 创建型模式-原型模式
*/
/* 结构
原型类ConcretePrototype:实现抽象原型类的 clone() 方法,它是可被复制的对象。
浅克隆 简单重写clone super.clone
深克隆方法 序列化 *** 注意原型的对象属性(Student)和原型都要实现Serializable
*/
public class PrototypeDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Student student = new Student("张三");
ConcretePrototype obj1 = new ConcretePrototype();
obj1.setName("原型初始值的名称属性是name1");
obj1.setStudent(student);
ConcretePrototype obj2 = obj1.clone();
ConcretePrototype obj3 = obj1.deepClone();
System.out.println("原型对象: " + obj1.getName() + "---学生属性值" + obj1.getStudent().getName());
System.out.println("克隆对象1: " + obj2.getName() + "---学生属性值" + obj2.getStudent().getName());
System.out.println("克隆对象2: " + obj3.getName() + "---学生属性值" + obj3.getStudent().getName());
obj1.setName("原型修改后的名称属性是name2");
student.setName("李四");
System.out.println("原型对象: " + obj1.getName() + "---学生属性值" + obj1.getStudent().getName());
System.out.println("克隆对象1: " + obj2.getName() + "---学生属性值" + obj2.getStudent().getName());
System.out.println("克隆对象2: " + obj3.getName() + "---学生属性值" + obj3.getStudent().getName());
System.out.println("obj1==obj2?" + (obj1 == obj2));
}
}
class ConcretePrototype implements Cloneable, Serializable {
private String name;
private Student student;
ConcretePrototype() {
System.out.println("原型创建成功!");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setStudent(Student student) {
this.student = student;
}
public Student getStudent() {
return student;
}
public ConcretePrototype clone() throws CloneNotSupportedException {
System.out.println("原型复制成功!");
return (ConcretePrototype) super.clone();
}
//深拷贝 - 方式 2 通过对象的序列化实现 (推荐)
public ConcretePrototype deepClone() {
try {
//序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos); //当前这个对象以对象流的方式输出
oos.writeObject(this);
//反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
ConcretePrototype cloneObject = (ConcretePrototype) ois.readObject();
return (ConcretePrototype)cloneObject;
}catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
class Student implements Serializable{
private String name;
Student(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
结构模式包含:
适配器模式,代理模式,桥接模式,组合模式,享元模式,外观模式,装饰模式
适配器模式 :
两个不兼容的接口之间的桥梁,将一个类接口转换成客户希望的另一个接口,使原本不兼容的类能一起工作(如将220v电压转换成5V电压),适配模式分为类适配模式和对象适配模式,前者使适配器继承目标方式,后者是将被适配类组合到适配器中转换。相较继承组合更灵活,如springMVC中handlerAdapter
结构:
- 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
- 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
- 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
![]() | ![]() |
![]() |
/*创建型模式之适配器模式 结构
目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。
更多实例:https://www.runoob.com/design-pattern/adapter-pattern.html
http://c.biancheng.net/view/1361.html
*/
public class AdpterDemo {
public static void main(String[] args) {
AdpteeToTargetAdpter1 target = new AdpteeToTargetAdpter1();
String res = target.functionA();
System.out.println(res);
AdpteeToTargetAdpter2 target1 = new AdpteeToTargetAdpter2();
Adptee adptee = new Adptee();
target1.setAdptee(adptee);
String res1 = target1.functionB();
System.out.println(res1);
//输出结果
/*已通过类模式,类继承方式适配将220v电压转换成5V电压
已通过对象模式,组合方式适配将220v电压转换成10V电压*/
}
}
//目标接口
interface Target {
String functionA();
String functionB();
}
class Adptee {
String functionC() {
return "220v电压";
}
}
//类继承方式 类模式
class AdpteeToTargetAdpter1 extends Adptee implements Target {
static final String typename = "类模式,类继承方式适配";
@Override
public String functionA() {
//do something
String original = this.functionC();
return "已通过" + typename + "将" + original + "转换成5V电压";
}
@Override
public String functionB() {
//do something
String original = this.functionC();
return "已通过" + typename + "将" + original + "转换成10V电压";
}
}
//组合方式 对象模式
class AdpteeToTargetAdpter2 implements Target {
static final String typename = "对象模式,组合方式适配";
private Adptee adptee = null;
public void setAdptee(Adptee adptee) {
this.adptee = adptee;
}
public String functionA() {
//do something
String original = this.adptee.functionC(); //实际上将对象方法封装到要实现的接口方法中
return "已通过" + typename + "将" + original + "转换成5V电压";
}
public String functionB() {
//do something
String original = this.adptee.functionC(); //实际上将对象方法封装到要实现的接口方法中
return "已通过" + typename + "将" + original + "转换成10V电压";
}
}
代理模式 :
为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象。代理模式有不同的形式, 主要有三种 静态代理、动态代理 (JDK 代理、接口代理)和 Cglib 代理 (可以在内存动态的创建对象,而不需要实现接口, 他是属于动态代理的范畴)。可以起到保护和增强目标对象的作用。
需要重点关注的是,代理的生成是大多是通过反射的机制,此处的反射也是一个重点。
以上过程就叫作字节码重组。
JDK 中有一个规范,在 ClassPath 目录下只要是 $ 开头的 .class 文件,一般都是自动生成的。
- 静态:其特点是代理类和目标类在代码中是确定的,因此称为静态。静态代理可以在不修改目标对象功能的前提下,对目标功能进行扩展。(缺点:真实主题与代理主题一一对应,增加真实主题也要增加代理,设计代理以前真实主题必须事先存在,不太灵活)
- 动态:也叫 JDK 代理或接口代理,在程序运行时,运用反射机制动态创建而成(如: SpringAOP)
-
java.lang.reflect.Proxy
- JDK 动态代理采用字节重组,重新生成对象来替代原始对象,以达到动态代理的目的。JDK 动态代理生成对象的步骤大致如下。
- 获取被代理对象的引用,并且获取它的所有接口。
- JDK 动态代理类重新生成一个新的类,同时新的类要实现被代理类实现的所有接口。
- 动态生成 Java 代码,新加的业务逻辑方法由一定的逻辑代码调用(在代码中体现),拿到被代理对象的引用。
- 编译新生成的 Java 代码 .class 字节码文件。
- 重新加载到 JVM 中运行。
结构:
- 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
- 真实主题(Real Subject / targetObject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
- 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
//抽象角色(动态代理只能代理接口)
interface Subject {
public void request();
}
//真实角色:实现了Subject的request()方法
class RealSubject implements Subject {
public void request() {
System.out.println("From real subject.");
}
}
//动态代理类
class DynamicProxy implements InvocationHandler{
Object obj;
public DynamicProxy(Subject target) {
this.obj = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before calling " + method);
method.invoke(obj, args);
System.out.println("after calling " + method);
return null;
}
}
public class DynamicProxyTest {
public static void main(String[] args) {
Subject target = new RealSubject();
DynamicProxy handler = new DynamicProxy(target);
Subject targetProxy =(Subject) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
targetProxy.request();
}
}
享元模式:
享元(FlyWeight)模式顾名思义,既是轻量级的,原因就是享元,共享元素,这里的元素指的是对象。减少对象数量节约内存,比如活字印刷术。
使用过程,一个工厂类将可以共享的对象存储到一个模式池(pool)中,每次使用对象前先到池中检查对象是否存在,如存在则直接使用,不存在生成对象并保存到pool中。往往与工厂模式单例模式一起使用。
java中的应用场景:如Integer与int的自动装箱与拆箱的设计,自动装箱时对于在-128~127之内的数值,它们被装箱为Integer对象后,会存在内存中被重用,在-128~127之外的数,被装箱后的Integer对象并不会被重用,即相当于每次装箱时都新建一个 Integer对象。
实例1:https://www.cnblogs.com/zyrblog/p/9250726.html
实例2:一个类CD包含三个属性创建年份year,名称name两个属性,多个CD对象中创建年份可能重复是可共享元flyweight,名称不会重复是不可共享元。
实例3:五子棋
棋子(ChessPieces)类是抽象享元角色,它包含了一个落子的 DownPieces(Graphics g,Point pt) 方法;
白子(WhitePieces)和黑子(BlackPieces)类是具体享元角色,它实现了落子方法;
Point 是非享元角色,它指定了落子的位置;
WeiqiFactory 是享元工厂角色,它通过 ArrayList 来管理棋子,并且提供了获取白子或者黑子的 getChessPieces(String type) 方法;
客户类(Chessboard)利用 Graphics 组件在框架窗体中绘制一个棋盘,并实现 mouseClicked(MouseEvent e) 事件处理方法,该方法根据用户的选择从享元工厂中获取白子或者黑子并落在棋盘上。
共享池
private static final HashMap<String, Flyweight> flyweights = new HashMap<String, Flyweight>();
flyweight = new ConcreteFlyweight(key);
flyweights.put(key, flyweight);
(Flyweight) flyweights.get(key);
private static final HashMap<String, Shape> circleMap = new HashMap<>();
circleMap.put(color, circle);
(Circle)circleMap.get(color);
private ArrayList<Flyweight> fws = new ArrayList<Flyweight>();
Flyweight fw = new ConcreteFlyweight();
fws.add(fw)
(Flyweight)fws.get(key)
private static Map<String, Ticket> sticketPool = new ConcurrentHashMap<String, Ticket>();
Ticket ticket = new TrainTicket(from, to);
TicketFactory.sticketPool.put(key, ticket);
(Ticket)TicketFactory.sticketPool.get(key);
结构:
- 抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
- 具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。
- 非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
- 享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
public class FlyWeightDemo {
public static void main(String[] args) {
new ChessBoard();
}
}
//棋盘
class ChessBoard extends MouseAdapter {
JFrame f;
Graphics g;
JRadioButton wb; //白子选项
JRadioButton bb; //黑子选项
ChessFactory cf;
private final int x = 50;
private final int y = 50;
private final int w = 40;
private final int rw = 400;
ChessBoard(){
f = new JFrame("享元模式在五子棋游戏中的应用");
f.setBounds(100, 100, 500, 550);
f.setVisible(true);
f.setResizable(false);
f.setLocation(800, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel TypePanel = new JPanel();
wb = new JRadioButton("白子");
bb = new JRadioButton("黑子",true);
ButtonGroup group = new ButtonGroup();
group.add(wb);
group.add(bb);
TypePanel.add(wb);
TypePanel.add(bb);
f.add(BorderLayout.NORTH, TypePanel);
JPanel chessPanel = new JPanel();
chessPanel.setLayout(null);
chessPanel.setSize(500,500);
chessPanel.addMouseListener(this);
f.add(BorderLayout.CENTER, chessPanel);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
g = chessPanel.getGraphics();
g.setColor(Color.BLUE);
g.drawRect(x, y, rw, rw);
for (int i = 1; i < 10; i++) {
//绘制第i条竖直线
g.drawLine(x + (i * w), y, x + (i * w), y + rw);
//绘制第i条水平线
g.drawLine(x, y + (i * w), x + rw, y + (i * w));
}
cf = new ChessFactory();
}
@Override
public void mouseClicked(MouseEvent e) {
Point p = new Point(e.getX()-15, e.getY()-15);
if(wb.isSelected()){
ChessPieces wcp = cf.getChessPiece("w");
wcp.downPieces(g, p);
wb.setSelected(false);
bb.setSelected(true);
}else{
ChessPieces bcp = cf.getChessPiece("b");
bcp.downPieces(g, p);
bb.setSelected(false);
wb.setSelected(true);
}
}
}
interface ChessPieces{
void downPieces(Graphics g, Point p);
}
class WhiteChessPiece implements ChessPieces{
@Override
public void downPieces(Graphics g, Point p) {
g.setColor(Color.WHITE);
g.fillOval(p.x, p.y, 30, 30);
}
}
class BlackChessPiece implements ChessPieces{
@Override
public void downPieces(Graphics g, Point p) {
g.setColor(Color.BLACK);
g.fillOval(p.x, p.y, 30, 30);
}
}
class ChessFactory {
private ArrayList<ChessPieces> chessList = new ArrayList<ChessPieces>();
public ChessFactory(){
ChessPieces wc = new WhiteChessPiece();
ChessPieces bc = new BlackChessPiece();
chessList.add(wc);
chessList.add(bc);
}
public ChessPieces getChessPiece(String type){
if (type.equals("w")){
return (ChessPieces) chessList.get(0);
}else if (type.equals("b")){
return (ChessPieces) chessList.get(1);
}else {
return null;
}
}
}
桥接模式:
将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
如:开关与电器的关系,开关可以是各种开关,电器可以是灯泡,风扇电视等。在开关类里面组合一个电器对象,开关的on,off方法中分别使用电器的打开和关闭。设计模式之桥接模式(Bridge) - 朱优良 - 博客园
桥接模式结构:
抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。
实例1 http://c.biancheng.net/view/1364.html
实例2 http://c.biancheng.net/view/8458.html
实例3 http://c.biancheng.net/view/8460.html
实例4 https://www.runoob.com/design-pattern/bridge-pattern.html
public class BridgeDemo {
public static void main(String[] args) {
Implementor impl = new ConcreteImplementor();
Abstraction abstraction = new RefinedAbstraction(impl);
abstraction.Operation();
}
}
//实现化角
interface Implementor {
public void OperationImpl();
}
//具体实现化
class ConcreteImplementor implements Implementor {
@Override
public void OperationImpl() {
System.out.println("具体实现化(Concrete Implementor)角色被访问");
}
}
//扩展抽象化
abstract class Abstraction {
protected Implementor impl;
protected Abstraction(Implementor impl) {
this.impl = impl;
}
public abstract void Operation();
}
//抽象化
class RefinedAbstraction extends Abstraction {
protected RefinedAbstraction(Implementor impl) {
super(impl);
}
@Override
public void Operation() {
System.out.println("扩展抽象化(Refined Abstraction)角色被访问");
impl.OperationImpl();
}
}
装饰器模式:
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。装饰器模式在 Java 语言中的最著名的应用莫过于 Java I/O 标准库的设计了。例如,InputStream 的子类 FilterInputStream,OutputStream 的子类 FilterOutputStream,Reader 的子类 BufferedReader 以及 FilterReader,还有 Writer 的子类 BufferedWriter、FilterWriter 以及 PrintWriter 等,它们都是抽象装饰类。
装饰器模式结构。
- 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。(需要被装饰的类的抽象类)
- 具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。(需要被装饰的类)
- 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
- 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
public class DecoratorDemo {
public static void main(String[] args) {
Component component = new ConcreteComponent();
Component componentDecorator = new ConcreteDecorator(component);
componentDecorator.doSomething();
}
}
//构件接口 待装饰的类接口
interface Component {
void doSomething();
}
//构件 待装饰类
class ConcreteComponent implements Component {
@Override
public void doSomething() {
System.out.println("component对象原有功能");
}
}
//抽象装饰类
abstract class Decorator implements Component {
private Component component;
Decorator(Component component) {
this.component = component;
}
@Override
public void doSomething() {
component.doSomething();
}
}
//装饰类
class ConcreteDecorator extends Decorator {
ConcreteDecorator(Component component) {
super(component);
}
@Override
public void doSomething() {
super.doSomething();
doMoreThing();
}
public void doMoreThing() {
System.out.println("component对象新功能");
}
}
外观模式:
如置办房产,客户需要分别去部门1,2,3……办理各种手续。简化业务流程后客户只需去一个部门办理相关手续, 这个部门负责客户所有其他手续的办理。这种简化模式就是外观模式。
定义:又叫作门面模式,是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。
模式的结构
- 外观(Facade)角色:为多个子系统对外提供一个共同的接口。
- 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。
实例:装饰器模式 | 菜鸟教程,外观模式(Facade模式)详解
public class FacedeDemo {
public static void main(String[] args) {
Facade facade = new Facade();
facade.method();
}
}
class Facade {
private SubSystem01 obj1 = new SubSystem01();
private SubSystem02 obj2 = new SubSystem02();
private SubSystem03 obj3 = new SubSystem03();
public void method(){
obj1.method1();
obj2.method2();
obj3.method3();
}
}
class SubSystem01 {
public void method1() {
System.out.println("子系统01的method1()被调用!");
}
}
class SubSystem02 {
public void method2() {
System.out.println("子系统02的method2()被调用!");
}
}
class SubSystem03 {
public void method3() {
System.out.println("子系统03的method3()被调用!");
}
}
组合模式
有时又叫作整体-部分(Part-Whole)模式,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性,属于结构型设计模式。
使用场景:常被用于部分、整体场景,如树形菜单,文件、文件夹的管理。
结构:
- 抽象构件(Component)角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)
- 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。
- 树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。
透明组合模式
安全组合模式
实例1 无限极文件目录结构 http://c.biancheng.net/view/8474.html
实例2 教程目录http://c.biancheng.net/view/8473.html
interface Component{
void doSomething();
}
class Leaf implements Component{
private String name;
Leaf(String name){
this.name = name;
}
@Override
public void doSomething() {
System.out.println("所有树枝和树叶都有的方法,这是树叶");
}
}
class Composite implements Component{
ArrayList<Component> items = new ArrayList<Component>();
@Override
public void doSomething() {
System.out.println("所有树枝和树叶都有的方法,这是树枝");
for (Component c:items){
c.doSomething(); //此处是递归算法
}
}
public void add(Component c){
items.add(c);
}
public void remove(Component c){
items.remove(c);
}
}
行为模式包括
模板方法模式:
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式。
结构:
- 抽象类(模板类):包含一个所有子类都拥有的公共方法(可以加上final),不能被重写。一些抽象方法,将由子类实现具体内容。其他方法可以被重写。
- 具体类:实现抽象类中的抽象方法
策略模式:
将多种解决问题的策略分别封装成单独的类供客户挑选使用。(封装多种策略类,环境类是对一种策略的引用)。
结构:
- 抽象策略类(strategy):定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
- 具体策略类(concreteStrategy1,concreteStrategy2,concreteStrategy3…… )实现了抽象策略定义的接口,提供具体的算法实现。
- 环境类(context)持有一个策略类的引用,最终给客户端调用。
//实例 两个数字的处理算法
public class StrategyDemo {
public static void main(String[] args) {
Context context = new Context(new Add());
System.out.println("10 + 5 = " + context.getResult(10, 5));
context = new Context(new Subtract());
System.out.println("10 - 5 = " + context.getResult(10, 5));
context = new Context(new Multiply());
System.out.println("10 * 5 = " + context.getResult(10, 5));
}
}
interface Strategy{
int Operation(int num1, int num2);
}
class Add implements Strategy{
@Override
public int Operation(int num1, int num2) {
return num1+num2;
}
}
class Subtract implements Strategy{
@Override
public int Operation(int num1, int num2) {
return num1-num2;
}
}
class Multiply implements Strategy{
@Override
public int Operation(int num1, int num2) {
return num1*num2;
}
}
class Context{
private Strategy concreteStrategy;
Context(Strategy concreteStrategy){
this.concreteStrategy = concreteStrategy;
}
int getResult(int num1, int num2){
return concreteStrategy.Operation(num1, num2);
}
}
命令模式:
命令模式,是将不同功能的对象封装到同一个类(command)中,等待调用者(invoker)使用,command中的一个是属性是执行者对象(receiver),不同的命令含有相同的执行对象。调用者与执行者不直接联系而是通过Command间接联系。这样调用者与执行者之间就完成了解耦操作。
实例1 将post,put,get,delete封装到统一的request中,客户端通过request向服务端发起请求
实例2 服务员,订购菜单,厨师。服务员通过订购菜单调用厨师做菜。订购菜单就是那个command类
实例3 电视机遥控器(命令发送者)通过按钮(具体命令)来遥控电视机(命令接收者)。
结构:调用者→命令→接受者
- 抽象命令类(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法 execute()。
- 具体命令类(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
- 实现者/接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
- 调用者/请求者(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。
public class CommandDemo {
public static void main(String[] args) {
Receiver receiver = new Receiver(10, 5);
Command concreteCmd = new AddCmd(receiver);
concreteCmd.execute();
Command concreteCmd1 = new SubtractCmd(receiver);
Invoker invoker = new Invoker(concreteCmd1);
invoker.call();
}
}
//命令执行者 执行过程细节
class Receiver {
private int num1;
private int num2;
Receiver(int num1, int num2){
this.num1 = num1;
this.num2 = num2;
}
void add(){
System.out.println(num1 + "+" + num2 + "=" + (num1+num2));
}
void subtract(){
System.out.println(num1 + "-" + num2 + "=" + (num1-num2));
}
void multiply(){
System.out.println(num1 + "*" + num2 + "=" + (num1*num2));
}
}
//抽象命令类
abstract class Command{
protected Receiver receiver;
void setCommand(Receiver receiver){
this.receiver = receiver;
}
abstract void execute();
}
class AddCmd extends Command{
AddCmd(Receiver receiver){
setCommand(receiver);
}
@Override
void execute() {
receiver.add();
}
}
class SubtractCmd extends Command{
SubtractCmd(Receiver receiver){
setCommand(receiver);
}
@Override
void execute() {
receiver.subtract();
}
}
class MultiplyCmd extends Command{
void MultiplyCmd(Receiver receiver){
setCommand(receiver);
}
@Override
void execute() {
receiver.multiply();
}
}
class Invoker {
private Command concreteCmd;
Invoker(Command concreteCmd){
this.concreteCmd = concreteCmd;
}
void call(){
this.concreteCmd.execute();
}
}
工厂模式 策略模式 命令模式容易混淆,但实际他们有明显区别
策略模式是通过不同的算法做同一件事情:例如排序,是含有不同的算法,做相同的事情,由上下文封装具体的策略类,策略类具体执行。
而命令模式则是通过不同的命令做不同的事情,常含有(关联)接收者,解耦请求者和接收者,是含有不同的命令(含有接收者的请求):做不同的事情;隐藏接收者执行细节,命令封装具体的命令接收者,命令接收者负责具体实现。 由invoker调用命令。
实例比较:【转】策略模式与命令模式区别 - 晨~光 - 博客园
责任链模式:
为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
职责链模式存在以下两种情况。
- 纯的职责链模式:一个请求必须被某一个处理者对象所接收,且一个具体处理者对某个请求的处理只能采用以下两种行为之一:自己处理(承担责任);把责任推给下家处理。
- 不纯的职责链模式:允许出现某一个具体处理者对象在承担了请求的一部分责任后又将剩余的责任传给下家的情况,且一个请求可以最终不被任何接收端对象所接收。
结构
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
public class chainOfResponsibilityDemo {
public static void main(String[] args) {
//组装责任链
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
handler1.setNext(handler2);
handler2.setNext(handler3);
//提交请求
handler1.handleRequest("one2");
}
}
//抽象处理者
abstract class Handler {
Handler next;
public void setNext(Handler next) {
this.next = next;
}
public Handler getNext() {
return next;
}
abstract void handleRequest(String request);
}
//具体处理者1
class ConcreteHandler1 extends Handler {
@Override
void handleRequest(String request) {
if (request.equals("one")) {
System.out.println("request of '" + request + "' 已在具体处理者1:" + this.getClass() + ",中被处理");
} else {
if (getNext() != null) {
getNext().handleRequest(request);
} else {
System.out.println("request of '" + request + "'没有处理者,当前所在链为具体处理者1" + this.getClass());
}
}
}
}
//具体处理者2
class ConcreteHandler2 extends Handler {
@Override
void handleRequest(String request) {
if (request.equals("two")) {
System.out.println("request of '" + request + "' 已在具体处理者2:" + this.getClass() + ",中被处理");
} else {
if (getNext() != null) {
getNext().handleRequest(request);
} else {
System.out.println("request of '" + request + "' 没有处理者,当前所在链为具体处理者2:" + this.getClass());
}
}
}
}
//具体处理者3
class ConcreteHandler3 extends Handler {
@Override
void handleRequest(String request) {
if (request.equals("three")) {
System.out.println("request of '" + request + "' 已在具体处理者3:" + this.getClass() + ",中被处理");
} else {
if (getNext() != null) {
getNext().handleRequest(request);
} else {
System.out.println("request of '" + request + "' 没有处理者,当前所在链为具体处理者3:" + this.getClass());
}
}
}
}
状态模式:
状态模式把受环境改变的对象行为包装在不同的状态对象里,其意图是让一个对象在其内部状态改变的时候,其行为也随之改变。
结构: context和state互相组合
- 环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
- 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
- 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。
状态模式与责任链模式的区别:状态模式和责任链模式都能消除 if-else 分支过多的问题。但在某些情况下,状态模式中的状态可以理解为责任,那么在这种情况下,两种模式都可以使用。从定义来看,状态模式强调的是一个对象内在状态的改变,而责任链模式强调的是外部节点对象间的改变。从代码实现上来看,两者最大的区别就是状态模式的各个状态对象知道自己要进入的下一个状态对象,而责任链模式并不清楚其下一个节点处理对象,因为链式组装由客户端负责。
状态模式与策略模式的区别:状态模式和策略模式的 UML 类图架构几乎完全一样,但两者的应用场景是不一样的。策略模式的多种算法行为择其一都能满足,彼此之间是独立的,用户可自行更换策略算法,而状态模式的各个状态间存在相互关系,彼此之间在一定条件下存在自动切换状态的效果,并且用户无法指定状态,只能设置初始状态
实例:状态模式(详解版), 状态模式 | 菜鸟教程
public class StateDemo {
public static void main(String[] args) {
}
}
//环境类
class Context{
private State state;
Context(){
this.state = new ConcreteStateA();
}
public void setState(State state) {
this.state = state;
}
public State getState() {
return state;
}
public void stateHandle(){
state.handle(this);
}
}
//抽象状态
abstract class State{
abstract void handle(Context context);
}
//具体状态类A
class ConcreteStateA extends State{
@Override
void handle(Context context) {
System.out.println("当前状态是 A.");
context.setState(new ConcreteStateB());
}
}
//具体状态类B
class ConcreteStateB extends State{
@Override
void handle(Context context) {
System.out.println("当前状态是 B.");
context.setState(new ConcreteStateA());
}
}
观察者模式(Observer):
多个对象依赖一个对象,当这个对象发生改变并通知依赖它的多个对象,所有依赖于它的对象收到通知后进行自我更新。
结构:
- 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
- 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
- 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
- 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
public class ObserverDemo {
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
subject.add(new ConcreteObserver1());
subject.add(new ConcreteObserver2());
subject.notifyObserver();
}
}
abstract class Subject {
protected List<Observer> observers = new ArrayList<Observer>();
void add(Observer observer) {
observers.add(observer);
}
void remove(Observer observer) {
observers.remove(observer);
}
abstract void notifyObserver();
}
class ConcreteSubject extends Subject {
@Override
void notifyObserver() {
for (Observer observer : observers) {
((Observer) observer).response();
}
}
}
//抽象观察者
interface Observer {
void response(); //反应
}
class ConcreteObserver1 implements Observer {
@Override
public void response() {
System.out.println("具体观察者1作出反应!");
}
}
class ConcreteObserver2 implements Observer {
@Override
public void response() {
System.out.println("具体观察者2作出反应!");
}
}
中介者模式:
将对象之间的通信关联关系封装到一个中介类中单独处理,从而使其耦合松散
迭代器模式
定义:
结构:
备忘录模式
定义:
结构:
解释器模式
定义:
结构:
访问者模式
定义:
结构:
分类 | 设计模式 | 简述 | 一句话归纳 | 目的 | 生活案例 |
---|---|---|---|---|---|
创建型设计模式 (简单来说就是用来创建对象的) | 工厂模式(Factory Pattern) | 不同条件下创建不同实例 | 产品标准化,生产更高效 | 封装创建细节 | 实体工厂 |
单例模式(Singleton Pattern) | 保证一个类仅有一个实例,并且提供一个全局访问点 | 世上只有一个我 | 保证独一无二 | CEO | |
原型模式(Prototype Pattern) | 通过拷贝原型创建新的对象 | 拔一根猴毛,吹出千万个 | 高效创建对象 | 克隆 | |
建造者模式(Builder Pattern) | 用来创建复杂的复合对象 | 高配中配和低配,想选哪配就哪配 | 开放个性配置步骤 | 选配 | |
结构型设计模式 (关注类和对象的组合) | 代理模式(Proxy Pattern) | 为其他对象提供一种代理以控制对这个对象的访问,即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。 | 没有资源没时间,得找别人来帮忙 | 增强职责 | 媒婆 |
外观模式(Facade Pattern) | 为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。 | 打开一扇门,通向全世界 | 统一访问入口 | 前台 | |
装饰器模式(Decorator Pattern) | 动态地为对象添加新功能 | 他大舅他二舅都是他舅 | 灵活扩展、同宗同源 | 煎饼 | |
享元模式(Flyweight Pattern) | 运用共享技术来有效地支持大量细粒度对象的复用。使用对象池来减少重复对象的创建 | 优化资源配置,减少重复浪费 | 共享资源池 | 全国社保联网 | |
组合模式(Composite Pattern) | 将整体与局部(树形结构)进行递归组合,使用户对单个对象和组合对象具有一致的访问性。 | 人在一起叫团伙,心在一起叫团队 | 统一整体和个体 | 组织架构树 | |
适配器模式(Adapter Pattern) | 将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。 | 万能充电器 | 兼容转换 | 电源适配 | |
桥接模式(Bridge Pattern) | 将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现的,从而降低了抽象和实现这两个可变维度的耦合度。 | 约定优于配置 | 不允许用继承 | 灯泡-开关-电线 | |
行为型设计模式 (关注对象之间的通信) | 模板模式(Template Pattern) | 定义一套流程模板,根据需要实现模板中的操作 | 流程全部标准化,需要微调请覆盖 | 逻辑复用 | 把大象装进冰箱 |
策略模式(Strategy Pattern) | 封装不同的算法,算法之间能互相替换 | 条条大道通罗马,具体哪条你来定 | 把选择权交给用户 | 选择支付方式 | |
责任链模式(Chain of Responsibility Pattern) | 拦截的类都实现统一接口,每个接收者都包含对下一个接收者的引用。将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。 | 各人自扫门前雪,莫管他们瓦上霜 | 解耦处理逻辑 | 踢皮球 | |
迭代器模式(Iterator Pattern) | 提供一种方法顺序访问一个聚合对象中的各个元素 | 流水线上坐一天,每个包裹扫一遍 | 统一对集合的访问方式 | 逐个检票进站 | |
命令模式(Command Pattern) | 将请求封装成命令,并记录下来,能够撤销与重做 | 运筹帷幄之中,决胜千里之外 | 解耦请求和处理 | 遥控器 | |
状态模式(State Pattern) | 根据不同的状态做出不同的行为 | 状态驱动行为,行为决定状态 | 绑定状态和行为 | 订单状态跟踪 | |
备忘录模式(Memento Pattern) | 保存对象的状态,在需要时进行恢复 | 失足不成千古恨,想重来时就重来 | 备份、后悔机制 | 草稿箱 | |
中介者模式(Mediator Pattern) | 将对象之间的通信关联关系封装到一个中介类中单独处理,从而使其耦合松散 | 联系方式我给你,怎么搞定我不管 | 统一管理网状资源 | 朋友圈 | |
解释器模式(Interpreter Pattern) | 给定一个语言,定义它的语法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子 | 我想说”方言“,一切解释权都归我 | 实现特定语法解析 | 摩斯密码 | |
观察者模式(Observer Pattern) | 状态发生改变时通知观察者,一对多的关系 | 到点就通知我 | 解耦观察者与被观察者 | 闹钟 | |
访问者模式(Visitor Pattern) | 稳定数据结构,定义新的操作行为 | 横看成岭侧成峰,远近高低各不同 | 解耦数据结构和数据操作 | KPI考核 | |
委派模式(Delegate Pattern) | 允许对象组合实现与继承相同的代码重用,负责任务的调用和分配 | 这个需求很简单,怎么实现我不管 | 只对结果负责 | 授权委托书 |