导读:设计模式.学习推荐设计模式目录:22种设计模式 (refactoringguru.cn) 图说设计模式 — Graphic Design Patterns.(design-patterns.readthedocs.io).UML类图初见.什么是统一建模语言(UML)? (visu
学习推荐设计模式目录:22种设计模式 (refactoringguru.cn) 图说设计模式 — Graphic Design Patterns (design-patterns.readthedocs.io)
什么是统一建模语言(UML)? (visual-paradigm.com)
介绍
UML 是统一建模语言的简称,它是一种由一整套图表组成的标准化建模语言。UML用于帮助系统开发人员阐明,展示,构建和记录软件系统的产出。UML代表了一系列在大型而复杂系统建模中被证明是成功的做法,是开发面向对象软件和软件开发过程中非常重要的一部分。UML主要使用图形符号来表示软件项目的设计,使用UML可以帮助项目团队沟通、探索潜在的设计和验证软件的架构设计。以下我们将向您详细介绍什么是UML、UML的历史以及每个UML图类型的描述,辅之以UML示例。
类图
类图是一切面向对象方法的核心建模工具。该图描述了系统中对象的类型以及它们之间存在的各种静态关系。
主要的关系:
表示是一个带有箭头的实线
带空心箭头
。空心菱形箭头
的直线表示实心菱形箭头
直线表示class结构
类名
成员变量 -:表示是private 修饰 +:表达使用public修饰 #:表示protected修饰 ~表示package/default
成员方法
UML图六种箭头含义 - 简书 (jianshu.com)
设计模式总结之模式分类_迷死特兔的博客-CSDN博客
它的主要特点是“将对象的创建与使用分离”
介绍
单例模式(Singleton Pattern):单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。
单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。单例模式是一种对象创建型模式。单例模式又名单件模式或单态模式。
实现单例模式步骤
new
运算符。如类图,将构造器私有使用getInstance()方法获得实列对象
通过名字简单了解一下,饿汉式一定会很饿
,在类初始化的时候就会创建该类的实列化对象
public class SingleObject {
//创建 SingleObject 的一个对象
private static SingleObject instance = new SingleObject();
//让构造函数为 private,这样该类就不会被实例化
private SingleObject(){}
//获取唯一可用的对象
public static SingleObject getInstance(){
return instance;
}
public void showMessage(){
System.out.println("Hello World!");
}
}
存在弊端:可能会占用大量资源,比如该类里面的成员变量会比较大,在我不需要使用该类之前,这个资源应该是想要空闲。
在我需要使用该类之后才创建该类的实列对象
基本懒汉式
描述: 这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
在多个进程同时调用getInstance时会出现创建了多个实列对象。解决办法我们可以想到使用锁(synchronized)来实现多线程安全
public class Singleton {
private static Singleton instance;
private Singleton (){}
//当需要的时候创建。
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
加锁了的懒汉式
描述: 这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
DCL懒汉式(双检锁/双重校验锁)
描述: 这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
注意:这里的singleton对象是加了Volatile
,因为singleton=new Singleton();不是一个原子性操作,主要分为3步来实现
给 singleton 分配内存
调用 Singleton 的构造函数来初始化成员变量,形成实例
将singleton对象指向分配的内存空间(执行完这步 singleton才是非 null 了)
这就又可能会发生指令重排,造成了132顺序,如果是这个顺序的话,就会出现线程A已经执行了3,准备执行2之前,有一个线程来执行getSingleton()方法,判断singleton是否等于NULL,这是线程A已经执行了3,singleton就不为NULL,于是线程B就返回singleton,造成线程B并获取到singleton的实列对象。
但是上面的方法并不是安全的,我们知道反射下面没有private.如果我们通过反射机制
直接使用静态方法来创建的话,是可以破坏单列模式的。
这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式是 Effective Java 作者 Josh Bloch
提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
OOP原则
实质介绍
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式(方法都是static修饰),它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例(工厂类(factory)),被创建的实例通常都具有共同的父类。
简单工厂模式包含如下角色:
工厂角色负责实现创建所有实例的内部逻辑
抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口
具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
下面这种方式违反了单一职责原则:
package Factroy;
public class SimpleFactory {
public static Car getCar(String name){
if(name.equals("wuling")){
return new wuling();
}else if(name.equals("Tesla")){
return new Tesla();
}
return null;
}
}
public class Tesla implements Car {
}
public class wuling implements Car {
}
public class Customer {
public static void main(String[] args) {
Car car=SimpleFactory.getCar("wuling");
}
}
进行简单优化,虽然也并不完全满足单一职责原则,违反了类上面的单一职责原则,但是符合方法上面的单一职责原则。
public class SimpleFactory {
public static Car getWulingCar(){
return new wuling();
}
public static Car getTeslaCar(){
return new Tesla();
}
}
工厂方法模式包含如下角色:
日志记录器
某系统日志记录器要求支持多种日志记录方式,如文件记录、数据库记录等,且用户可以根据要求动态选择日志记录方式, 现使用工厂方法模式设计该系统。
结构图:
在以下情况下可以使用工厂方法模式:
它能创建一系列相关的对象, 而无需指定其具体类,
与简单工厂模式和工厂方法模式区别
抽象工厂模式是创建一个产品群,而简单工厂和工厂方法是创建一个产品类型。
椅子
Chair 、 沙发
Sofa和 咖啡桌
CoffeeTable 。现代
Modern 、 维多利亚
Victorian 、 装饰风艺术
ArtDeco等风格生成 椅子
、 沙发
和 咖啡桌
。抽象工厂模式包含如下角色:
代码实现:
AbstractFactory
package AbstractFactory;
public interface IFactory {
IPhoneinterface Phone();
IRouterinterface Router();
}
ConcreteFactory1
package AbstractFactory;
public class xiaomiFactory implements IFactory {
@Override
public IPhoneinterface Phone() {
return new xiaomiPhone();
}
@Override
public IRouterinterface Router() {
return new xiaomiRouter();
}
}
ConcreteFactory2
package AbstractFactory;
public class huaweiFactory implements IFactory {
@Override
public IPhoneinterface Phone() {
return new huaweiPhone();
}
@Override
public IRouterinterface Router() {
return new huaweiRouter();
}
}
AbstractProductA
package AbstractFactory;
public interface IPhoneinterface {
void startUp();
void stop();
void takePhone();
}
AbstractProductB
package AbstractFactory;
public interface IRouterinterface {
void startup();
void stop();
void run();
}
ProductA1 ProductA2
package AbstractFactory;
public class xiaomiPhone implements IPhoneinterface {
@Override
public void startUp() {
System.out.println("小米手机开机");
}
@Override
public void stop() {
System.out.println("小米手机关机");
}
@Override
public void takePhone() {
System.out.println("小米手机打电话");
}
}
package AbstractFactory;
public class huaweiPhone implements IPhoneinterface {
@Override
public void startUp() {
System.out.println("华为手机开机");
}
@Override
public void stop() {
System.out.println("华为手机关机");
}
@Override
public void takePhone() {
System.out.println("华为手机打电话");
}
}
ProductB1 ProductB2
package AbstractFactory;
public class xiaomiRouter implements IRouterinterface {
@Override
public void startup() {
System.out.println("小米路由器开机");
}
@Override
public void stop() {
System.out.println("小米路由器关机");
}
@Override
public void run() {
System.out.println("小米路由运行");
}
}
package AbstractFactory;
public class huaweiRouter implements IRouterinterface {
@Override
public void startup() {
System.out.println("华为路由器开机");
}
@Override
public void stop() {
System.out.println("华为路由器关机");
}
@Override
public void run() {
System.out.println("华为路由运行");
}
}
在以下情况下可以使用抽象工厂模式:
产品族
,而每次只使用其中某一产品族。使你能够复制已有对象, 而又无需使代码依赖它们所属的类。
Spring Bean使用了原型模式和单例模式
getMergedBeanDefinition方法.cloneBeanDefinition()
if (mbd == null || mbd.stale) {
previous = mbd;
if (bd.getParentName() == null) {
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition)bd).cloneBeanDefinition();
} else {
mbd = new RootBeanDefinition(bd);
}
}
Arrays toArrAy
@Override
public Object[] toArray() {
return a.clone();
}
注意事项: 与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。我们在后面进行研究。
如图当我们已经拥有了实列对象obj1之后,在调用clone()方法。拷贝一份
将原型类 implements Cloneable接口
重写clone()方法。
package prototype; import java.util.Date; //①实现Cloneable接口 public class Video implements Cloneable { private String name; private Date date; //②重写clone方法 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
@Override
public String toString() {
return "Video{" +
"name='" + name + '\'' +
", date=" + date +
'}';
}
public Video(String name, Date date) {
this.name = name;
this.date = date;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
} package prototype;
import javax.swing.*; import java.util.Date;
public class PrototypeDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Date date=new Date();
Video v1 = new Video(“某UP主”, date);
Video v2 = (Video) v1.clone();
System.out.println(“V1的hashCode值”+v1.hashCode());
System.out.println(“V2的hashCode值”+v2.hashCode());
System.out.println(“V1”+v1.toString());
System.out.println(“V2”+v2.toString());
}
}
/*
V1的hashCode值356573597
V2的hashCode值1735600054
看出V1和V2是两个对象。
V1Video{name=‘某UP主’, date=Wed Aug 23 20:28:48 CST 2023}
V2Video{name=‘某UP主’, date=Wed Aug 23 20:28:48 CST 2023}
*/
浅拷贝与深拷贝
深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的 。
深拷贝和浅拷贝的示意图大致如下:
浅拷贝只复制指向 某个对象的指针(重新在堆中申请了一快内存,之后又重新指向了同一个成员变量),而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
判断我们上面的实列是属于浅拷贝还是深拷贝
package prototype;
import javax.swing.*;
import java.util.Date;
public class PrototypeDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Date date=new Date();
Video v1 = new Video("某UP主", date);
Video v2 = (Video) v1.clone();
date.setDate(123);
System.out.println("V1的hashCode值"+v1.hashCode());
System.out.println("V2的hashCode值"+v2.hashCode());
System.out.println("V1.Date的hashCode"+v1.getDate().hashCode());
System.out.println("V2.Date的hashCode"+v2.getDate().hashCode());
}
}
运行结果:
V1的hashCode值356573597
V2的hashCode值1735600054
V1.Date的hashCode123
V2.Date的hashCode123
//观察到V1和V2的Date成员变量是同一对象,所以我们上面的实列是属于浅拷贝
如何实现深拷贝
由于指向的是同一成员对象,那么我们可以改写clone方法将我们的成员变量也进行拷贝
@Override protected Object clone() throws CloneNotSupportedException { Object clone = super.clone(); Video V1 = (Video) clone; V1.date= (Date) this.date.clone(); return clone; }
package prototype;
import javax.swing.*; import java.util.Date;
public class PrototypeDemo { public static void main(String[] args) throws CloneNotSupportedException { Date date=new Date(); Video v1 = new Video(“某UP主”, date); Video v2 = (Video) v1.clone(); date.setTime(123); System.out.println(“V1的hashCode值”+v1.hashCode()); System.out.println(“V2的hashCode值”+v2.hashCode()); System.out.println(“V1.Date的hashCode”+v1.getDate().hashCode()); System.out.println(“V1.Date的hashCode”+v2.getDate().hashCode()); } } V1的hashCode值356573597 V2的hashCode值1735600054 V1.Date的hashCode123 V1.Date的hashCode579090841
同构序列化和反序列化实现深拷贝
序列化和反序列化是什么?
序列化:就是将对象转化成字节序列的过程。
反序列化:就是讲字节序列转化成对象的过程。
对象序列化成的字节序列会包含对象的类型信息、对象的数据等,说白了就是包含了描述这个对象的所有信息,能根据这些信息“复刻”出一个和原来一模一样的对象。这和我们的原型模式很像
为什么需要序列化
注意:
代码实现
// 实际的数据流向:ObjectOutputStream->ByteArrayOutputStream->ByteArrayInputStream ->ObjectInputStream,深度复制从序列化对象又转为序列化对象
public User copy() throws IOException, ClassNotFoundException {
// 序列化
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(this); // 将this对象 转变为 二进制字节流
// 反序列化
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
return (User) objectInputStream.readObject();
}
造者模式(Builder Pattern):将一个复杂对象
的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。建造者模式属于对象创建型模式。根据中文翻译的不同,建造者模式又可以称为生成器模式。
建造者模式包含如下角色:
将一个复杂的产品分配好步骤,最终得到一个完整的产品。与工厂模式不同的是工厂模式是生产相应的零件(一个实现类只是一个零件),而建造者模式会组合好相应的零件最后生产出完整的产品。
往往实列中需要将工厂模式和建造者模式相结合。
建造者模式可以用于描述KFC如何创建套餐:套餐是一个复杂对象,它一般包含主食(如汉堡、鸡肉卷等)和饮料(如果汁、 可乐等)等组成部分,不同的套餐有不同的组成部分,而KFC的服务员可以根据顾客的要求,一步一步装配这些组成部分,构造一份完整的套餐,然后返回给顾客。
代码实现
package Builder;
public class Worker extends Builder {
Product product;
public Worker() {
this.product = new Product();
}
@Override
public Product getProduct() {
return product;
}
@Override
Builder A(String msg) {
product.setA(msg);
return this;
}
@Override
Builder B(String msg) {
product.setB(msg);
return this;
}
@Override
Builder C(String msg) {
product.setC(msg);
return this;
}
@Override
Builder D(String msg) {
product.setD(msg);
return this;
}
}
package Builder;
public abstract class Builder {
abstract Builder A(String msg);
abstract Builder B(String msg);
abstract Builder C(String msg);
abstract Builder D(String msg);
abstract Product getProduct();
}
package Builder;
public class Product {
private String A;
private String B;
private String C;
private String D;
public String getA() {
return A;
}
public void setA(String a) {
A = a;
}
public String getB() {
return B;
}
public void setB(String b) {
B = b;
}
public String getC() {
return C;
}
public void setC(String c) {
C = c;
}
public String getD() {
return D;
}
public void setD(String d) {
D = d;
}
@Override
public String toString() {
return "Product{" +
"A='" + A + '\'' +
", B='" + B + '\'' +
", C='" + C + '\'' +
", D='" + D + '\'' +
'}';
}
}
package Builder;
public class Customer {
public static void main(String[] args) {
Worker watier = new Worker();
Product product = watier.A("汉堡").B("可乐").C("炸鸡").getProduct();
System.out.println(product);
}
}
在该案列中顾客相当于是一个指挥者,指挥着套餐如生产。套餐是那些。
该实例里面有专门的指挥者来指挥着建造的具体步骤
差异性很大
,则不适合使用建造者模式,因此其使用范围受到一定的限制。建造者模式的简化:
Builder角色扮演指挥者与建造者双重角色。
简单介绍
结构型模式(Structural Pattern) 描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构。
结构型模式可以分为 类结构型模式 和 对象结构型模式 :
适配器模式(Adapter Pattern) :将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
适配器模式包含如下角色:
适配器模式有对象适配器和类适配器两种实现:
对象适配器:
类适配器:
代码实现
package Adapter;
public class Target {
public void request(Adapter adapter){
adapter.Apadter();
}
public static void main(String[] args) {
Target target = new Target();
Adaptee adaptee = new Adaptee();
Adapter adapter = new Adapter(adaptee);
target.request(adapter);
}
}
public class Adapter implements NetToUSB {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void Apadter() {
adaptee.request();
}
}
public class Adaptee {
public void request(){
System.out.println("网线接入可以上网");
}
}
public interface NetToUSB {
void Apadter();
}
Java 核心程序库中有一些标准的适配器:
java.util.Arrays#asList()
java.util.Collections#list()
java.util.Collections#enumeration()
java.io.InputStreamReader(InputStream)
(返回 Reader
对象)java.io.OutputStreamWriter(OutputStream)
(返回 Writer
对象)javax.xml.bind.annotation.adapters.XmlAdapter#marshal()
和 #unmarshal()
由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。
对于Java、C#等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。
与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。
模式定义
桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
桥接模式包含如下角色:
代码实现
Abstraction
package Bridge;
public abstract class Shape {
//简历联系 (建好桥梁)
private Color color;
public Shape(Color color) {
this.color = color;
}
public void shape(){
color.color();
};
}
class Circle extends Shape{
public Circle(Color color) {
super(color);
}
@Override
public void shape() {
super.shape();
System.out.print("圆形");
}
}
class Rectangle extends Shape{
public Rectangle(Color color) {
super(color);
}
@Override
public void shape() {
super.shape();
System.out.println("矩形");
}
}
InterfaceImp
package Bridge;
public interface Color {
void color();
}
class red implements Color{
@Override
public void color() {
System.out.print("红色的");
}
}
class blue implements Color{
@Override
public void color() {
System.out.print("蓝色的");
}
}
package Bridge;
public class Test {
public static void main(String[] args) {
Circle circle = new Circle(new red());
circle.shape();
}
}
在Abstraction中使用组合将Interface作为成员变量建立连接,
代理模式(Proxy Pattern) :给某一个对象提供一个代 理,并由代理对象控制对原对象的引用。代理模式的英 文叫做Proxy或Surrogate,它是一种对象结构型模式。Spring AOP
静态代理: 所谓静态代理也就是在程序运行前就已经存在代理类的字节码文件(在真正结婚之前,就已经做好了相关工作,婚庆公司和结婚的人就做好了相关联系)。代理模式就是在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。简单来说静态代理就是在不改变源代码的基础上增加新的功能。
代理模式包含如下角色:
代码实现
package Proxy;
public interface Rent {
void renct();
}
package Proxy;
public class Proxy implements Rent {
private Host host;
public void setHost(Host host) {
this.host = host;
}
@Override
public void renct() {
//租房前
before();
host.renct(); //房东租房
after();
}
public void before(){
System.out.println("租房前需要确定的一些事情");
}
public void after(){
System.out.println("租房后需要做的一些事情");
}
}
package Proxy;
//房东需要租房
public class Host implements Rent {
@Override
public void renct() {
System.out.println("房东成功的将房子出租");
}
}
package Proxy;
import Builder.Product;
public class Customer {
public static void main(String[] args) {
Host host=new Host();
Proxy proxy=new Proxy();
proxy.setHost(host);
proxy.renct();
}
}
代理模式的优点
代理模式的缺点
基于反射实现,没有明确的代理类
动态代理分类:
jdk动态代理 代码实现
了解Proxy InvocationHandle
Proxy 获取代理对象
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class<?>[] { Foo.class },
handler);
proxy class 是在运行时创建的类,它实现了指定的接口列表,称为 proxy interfaces 。 proxy instance 是代理类的一个实例。每个代理实例都有一个关联的调用处理程序对象,它实现了接口 InvocationHandler 。通过其代理接口之一对代理实例的方法调用将被分派到实例调用处理程序的 invoke 方法,传递代理实例、标识被调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型数组.调用处理程序适当地处理编码的方法调用,并且它返回的结果将作为对代理实例的方法调用的结果返回。
InvocationHandle处理代理实例上的方法
Object invoke(Object proxy, Method method, Object [] args) throws Throwable
处理代理实例上的方法调用并返回结果。当在与其关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
动态代理类
package DynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Objects;
public class InvocationHalderImp implements InvocationHandler {
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//获取代理对象
public Object getTarget(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),
this);
}
//执行代理方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(rent, args);
after();
return result;
}
public void before(){
System.out.println("租房前需要确定的一些事情");
}
public void after(){
System.out.println("租房后需要做的一些事情");
}
}
测试
package DynamicProxy;
public class Client {
public static void main(String[] args) {
Rent host=new Host();
InvocationHalderImp invoke=new InvocationHalderImp();
invoke.setRent(host);
Rent target = (Rent) invoke.getTarget();
target.renct();
}
}
可以使用Arthus观察底层源码
执行流程如下:
Cglib代理
jdk动态代理的缺陷是基于接口,必须要实现接口才可以使用,如果不实现接口,可以使用基于类的Cglib动态代理。
Cglib是第三方提供的需要导入jar包
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
package DynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Objects;
public class InvocationHalderImp implements MethodInterceptor {
private Host rent;
public void setRent(Host rent) {
this.rent = rent;
}
//获取代理对象
public Object getTarget(){
// return Proxy.newProxyInstance(this.getClass().getClassLoader(),
// rent.getClass().getInterfaces(),
// this);
//创建Enhancer对象,类似于JDK代理中的Proxy类
Enhancer enhancer=new Enhancer();
//设置父类的字节码对象
enhancer.setSuperClass(Host.class);
//设置回调函数,参数是MethoInterceptor
enhancer.setCallback(this);
//创建代理
Host host=(Host) enhancer.create();
return host
}
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("======插入后者通知======");
return object;
}
}
public void before(){
System.out.println("租房前需要确定的一些事情");
}
public void after(){
System.out.println("租房后需要做的一些事情");
}
}
装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式。
装饰模式包含如下角色:
代码实现
Component抽象构建
package Decorator;
public abstract class FactFood {
private Integer price;
private String desc;
abstract Integer coat();
public FactFood(Integer price, String desc) {
this.price = price;
this.desc = desc;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
}
ComCreteComponent具体组件
package Decorator;
public class Factrice extends FactFood {
public Factrice() {
super(10,"炒饭");
}
@Override
Integer coat() {
return getPrice();
}
}
Decorator抽象装饰类
package Decorator;
public abstract class Decorator extends FactFood {
private FactFood fact;
public Decorator(FactFood fact, Integer price, String desc) {
super(price, desc);
this.fact=fact;
}
public FactFood getFact() {
return fact;
}
public void setFact(FactFood fact) {
this.fact = fact;
}
}
ConcreteDecorator具体装饰类
package Decorator;
public class Egg extends Decorator {
public Egg(FactFood factFood) {
super(factFood,1, "鸡蛋");
}
@Override
Integer coat() {
return getPrice()+getFact().getPrice();
}
@Override
public String getDesc() {
return super.getDesc()+getFact().getDesc();
}
}
外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。
外观模式包含如下角色:
外观模式的优点
外观模式的缺点
如果你需要一个指向复杂子系统
的直接接口, 且该接口的功能有限, 则可以使用外观模式。
子系统通常会随着时间的推进变得越来越复杂。 即便是应用了设计模式, 通常你也会创建更多的类。 尽管在多种情形中子系统可能是更灵活或易于复用的, 但其所需的配置和样板代码数量将会增长得更快。 为了解决这个问题, 外观将会提供指向子系统中最常用功能的快捷方式, 能够满足客户端的大部分需求。
如果需要将子系统组织为多层结构
, 可以使用外观。
创建外观来定义子系统中各层次的入口。 你可以要求子系统仅使用外观来进行交互, 以减少子系统之间的耦合。
javax.faces.context.ExternalContext
在内部使用了 ServletContext
、 HttpSession
、 HttpServletRequest
、 HttpServletResponse
和其他一些类。组合模式 是一种结构型设计模式, 你可以使用它将对象组合成树状结构, 并且能像使用独立对象
一样使用它们。
组合模式建议使用一个通用接口
来与 产品
和 盒子
进行交互
组件 (Component) 接口描述了树中简单项目和复杂项目所共有的操作。
叶节点 (Leaf) 是树的基本结构, 它不包含子项目。一般情况下, 叶节点最终会完成大部分的实际工作, 因为它们无法将工作指派给其他部分。
容器 (Container)——又名 “组合 (Composite)”——是包含叶节点或其他容器等子项目的单位。 容器不知道其子项目所属的具体类, 它只通过通用的组件接口与其子项目交互。容器接收到请求后会将工作分配给自己的子项目, 处理中间结果, 然后将最终结果返回给客户端。
客户端 (Client) 通过组件接口与所有项目交互。 因此, 客户端能以相同方式与树状结构中的简单或复杂项目交互。
打印文件名称
Component类
package Combine;
public abstract class Menucomponent {
String name;//文件名称
int level;//文件等级
public Menucomponent(String name, int level) {
this.name = name;
this.level = level;
}
public void addMenu(Menucomponent menucomponent){
throw new UnsupportedOperationException();
}
public void RemoveMenu(Menucomponent menucomponent){
throw new UnsupportedOperationException();
}
public Menucomponent GetMenu(int index){
throw new UnsupportedOperationException();
}
abstract void print();
}
Composite
package Combine;
import java.util.ArrayList;
import java.util.List;
public class Menu extends Menucomponent {
private List<Menucomponent> list=new ArrayList<>();
public Menu(String name, int level) {
super(name, level);
}
@Override
public void addMenu(Menucomponent menucomponent) {
list.add(menucomponent);
}
@Override
public void RemoveMenu(Menucomponent menucomponent) {
list.remove(menucomponent);
}
@Override
public Menucomponent GetMenu(int index) {
return list.get(index);
}
@Override
void print() {
for(int i=0;i<level;i++){
System.out.print("--");
}
System.out.println(name);
for (Menucomponent menucomponent : list) {
menucomponent.print();
}
}
}
Leaf叶子类
package Combine;
public class MenuIntem extends Menucomponent {
public MenuIntem(String name, int level) {
super(name, level);
}
@Override
void print() {
for (int i=0;i<this.level;i++){
System.out.print("--");
}
System.out.println(this.name);
}
}
Client
package Combine;
public class Client {
public static void main(String[] args) {
Menucomponent menu1=new Menu("菜单管理",2);
menu1.addMenu(new MenuIntem("页面访问",3));
menu1.addMenu(new MenuIntem("展开菜单",3));
menu1.addMenu(new MenuIntem("删除彩单",3));
menu1.addMenu(new MenuIntem("新增菜单",3));
Menucomponent menu2=new Menu("权限管理",2);
menu2.addMenu(new MenuIntem("页面访问",3));
menu2.addMenu(new MenuIntem("提交保存",3));
Menucomponent menu3=new Menu("角色管理",2);
menu3.addMenu(new MenuIntem("页面访问",3));
menu3.addMenu(new MenuIntem("新增角色",3));
menu3.addMenu(new MenuIntem("修改角色",3));
Menucomponent menu=new Menu("系统管理",1);
menu.addMenu(menu1);
menu.addMenu(menu2);
menu.addMenu(menu3);
menu.print();
}
}
享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。
池化技术。
享元模式包含如下角色:
代码实现
Flyweight
package FlyWeight;
public abstract class AbstractShap {
abstract String getShape();
public void getDesc(String Color){
System.out.println("形状="+getShape()+",颜色"+Color);
}
}
ConcreteFlyweight
package FlyWeight;
public class IBox extends AbstractShap{
@Override
String getShape() {
return "i";
}
}
FlyweightFactory
package FlyWeight;
import java.util.HashMap;
import java.util.Map;
public class ShapeFactory {
private static ShapeFoactory shapeFoactory=new ShapeFoactory();
private Map<String,AbstractShap> map;
public ShapeFoactory() {
map=new HashMap<>();
map.put("I",new IBox());
map.put("L",new LBox());
map.put("T",new TBox());
}
public static ShapeFoactory getInstance(){
return shapeFoactory;
}
public AbstractShap getShape(String name){
return map.get(name);
}
}
享元模式在JDK中的运用,如Integer
Integer在-128到127范围内,使用==作比较得到的答案是true,表示是用一对象,在范围之外使用 ==比较得到的答案是false表示不是同一对对象。所以在Integer使用了享元模式让Integer在范围-128到127里面的对象得到了多次使用
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
享元模式的优点
享元模式的缺点
行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。
行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。
通过行为型模式,可以更加清晰地划分类与对象的职责,并研究系统在运行时实例对象 之间的交互。在系统运行时,对象并不是孤立的,它们可以通过相互通信与协作完成某些复杂功能,一个对象在运行时也将影响到其他对象的运行。
行为型模式分为类行为型模式和对象行为型模式两种:
模板方法模式 是一种行为设计模式, 它在超类中(父类)定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。
抽象
类型, 也可以提供一些默认实现。代码实现
AbstractClass
package template;
public abstract class AbstractTemplateClass {
public final void Implenment(){
A();
B();
C();
D();
E();
}
public void A(){
System.out.println("第一步");
}
public void B(){
System.out.println("第二步");
}
abstract void C();
abstract void D();
public void E(){
System.out.println("第五步");
}
}
ConcreteClassA
package template;
public class ConcreteA extends AbstractTemplateClass {
@Override
void C() {
System.out.println("具体A类实现的C方法");
}
@Override
void D() {
System.out.println("具体A类实现的D方法");
}
}
ConcreteClassB
package template;
public class ConcreteB extends AbstractTemplateClass {
@Override
void C() {
System.out.println("具体B类实现的C方法");
}
@Override
void D() {
System.out.println("具体B类实现的D方法");
}
}
策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。
策略模式包含如下角色:
伪代码
// 策略接口声明了某个算法各个不同版本间所共有的操作。上下文会使用该接口来
// 调用有具体策略定义的算法。
interface Strategy is
method execute(a, b)
// 具体策略会在遵循策略基础接口的情况下实现算法。该接口实现了它们在上下文
// 中的互换性。
class ConcreteStrategyAdd implements Strategy is
method execute(a, b) is
return a + b
class ConcreteStrategySubtract implements Strategy is
method execute(a, b) is
return a - b
class ConcreteStrategyMultiply implements Strategy is
method execute(a, b) is
return a * b
// 上下文定义了客户端关注的接口。
class Context is
// 上下文会维护指向某个策略对象的引用。上下文不知晓策略的具体类。上下
// 文必须通过策略接口来与所有策略进行交互。
private strategy: Strategy
// 上下文通常会通过构造函数来接收策略对象,同时还提供设置器以便在运行
// 时切换策略。
method setStrategy(Strategy strategy) is
this.strategy = strategy
// 上下文会将一些工作委派给策略对象,而不是自行实现不同版本的算法。
method executeStrategy(int a, int b) is
return strategy.execute(a, b)
// 客户端代码会选择具体策略并将其传递给上下文。客户端必须知晓策略之间的差
// 异,才能做出正确的选择。
class ExampleApplication is
method main() is
创建上下文对象。
读取第一个数。
读取最后一个数。
从用户输入中读取期望进行的行为。
if (action == addition) then
context.setStrategy(new ConcreteStrategyAdd())
if (action == subtraction) then
context.setStrategy(new ConcreteStrategySubtract())
if (action == multiplication) then
context.setStrategy(new ConcreteStrategyMultiply())
result = context.executeStrategy(First number, Second number)
打印结果。
策略模式的优点
策略模式的缺点
命令模式(Command Pattern):将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。
命令模式包含如下角色:
代码实现
Command
package Command;
public interface Command {
void execute();
}
ConcreteCommand,必须要关联上执行值(Receiver)
package Command;
import java.util.Set;
public class OrderCommand implements Command {
private Receiver receiver;
private Order order;
public OrderCommand(Receiver receiver,Order order) {
this.receiver=receiver;
this.order=order;
}
@Override
public void execute() {
System.out.println("新的订单来了");
Set<String> keys = order.getMap().keySet();
for (String key : keys) {
Integer integer = order.getMap().get(key);
receiver.active(key,integer);
}
System.out.println(order.getTable()+"订单完成");
}
}
Receiver命令执行者
package Command;
public class Receiver {
public void active(String name,Integer num){
System.out.println(num+"份的"+name+"制作完成");
}
}
Invoke命令的调用者
package Command;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Invoke {
private List<OrderCommand> list=new ArrayList<>();
public void add(OrderCommand orderCommand){
list.add(orderCommand);
}
//发送命令执行
public void call(){
for (OrderCommand orderCommand : list) {
orderCommand.execute();
}
}
}
命令模式的优点
命令模式的缺点
在JDK中的实列
以下是在核心 Java 程序库中的一些示例:
java.lang.Runnable
的所有实现javax.swing.Action
的所有实现Runable是一个典型命令模式,Runnable担当命令的角色,,Thread充当的是调用者,start方法就是其执行方法
责任链模式 是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。
通用接口
。 该接口通常仅包含单个方法用于请求处理, 但有时其还会包含一个设置链上下个处理者的方法。代码实现
Handler
package Chain;
public abstract class Handler {
public static final Integer HOLIDAY_ONE = 1;
public static final Integer HOLIDAY_THREE = 3;
public static final Integer HOLIDAY_SEVEN = 7;
private Note note;
private Handler nextHandler;
private Integer start;
private Integer end;
public Note getNote() {
return note;
}
public void setNote(Note note) {
this.note = note;
}
public Handler getNextHandler() {
return nextHandler;
}
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void hanler();
public Handler(Integer start, Integer end) {
this.end = end;
this.start = start;
}
public final void submit() {
this.hanler();
if(this.nextHandler!=null&&this.note.getNum()>this.end){
this.nextHandler.setNote(this.note);
this.nextHandler.submit();
}else{
System.out.println("完毕");
}
}
}
ConcreteHandler
package Chain;
public class Groupmanager extends Handler {
public Groupmanager() {
super(0,Handler.HOLIDAY_ONE);
}
@Override
public void hanler() {
System.out.println(this.getNote().getName()+"因为"+this.getNote().getContent()+"需要请加"+this.getNote().getNum());
System.out.println("小组部长批准");
}
}
package Chain;
public class Manager extends Handler {
public Manager() {
super(Handler.HOLIDAY_THREE, Handler.HOLIDAY_SEVEN);
}
@Override
public void hanler() {
System.out.println(this.getNote().getName()+"因为"+this.getNote().getContent()+"需要请加"+this.getNote().getNum());
System.out.println("副经理批准");
}
}
package Chain;
public class GeneralManager extends Handler {
public GeneralManager() {
super(Handler.HOLIDAY_SEVEN,9);
}
@Override
public void hanler() {
System.out.println(this.getNote().getName()+"因为"+this.getNote().getContent()+"需要请假"+this.getNote().getNum());
System.out.println("总经理批准");
}
}
Client
package Chain;
public class Client {
public static void main(String[] args) {
Note note=new Note("小明",1,"身体不舒服");
Groupmanager group=new Groupmanager();
Manager manager=new Manager();
GeneralManager generalManager=new GeneralManager();
//建立责任链
group.setNextHandler(manager);
manager.setNextHandler(generalManager);
group.setNote(note);
group.submit();
}
}
Event事件类
package Chain;
public class Note {
private String name;
private Integer num;
private String content;
public String getName() {
return name;
}
public Integer getNum() {
return num;
}
public String getContent() {
return content;
}
public Note(String name, Integer num, String content) {
this.name = name;
this.num = num;
this.content = content;
}
}
javax.servlet.Filter#doFilter()
java.util.logging.Logger#log()
上一篇:百度网盘(百度云)SVIP超级会
下一篇:VSCode中的快捷键