视频讲解见b站“av57936239”。
视频配套的pdf文档,见本地电脑”/Users/herbert/Documents/java文档/尚硅谷设计模式源码笔记课件/笔记/尚硅谷_韩顺平_图解Java设计模式.pdf“
设计模式介绍 1) 设计模式是程序员在面对同类软件工程设计问题所总结出来的有用的经验,模式不是代码,而是某类问题的通 用解决方案,设计模式(Design pattern)代表了最佳的实践。这些解决方案是众多软件开发人员经过相当长的 一段时间的试验和错误总结出来的。 2) 设计模式的本质提高软件的维护性,通用性和扩展性,并降低软件的复杂度。 3) <<设计模式>> 是经典的书,作者是 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides Design(俗 称 “四人组 GOF”) 4) 设计模式并不局限于某种语言,java,php,c++ 都有设计模式. 设计模式类型 设计模式分为三种类型,共 23 种 1) 创建型模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。 2) 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。 3) 行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、 解释器模式(Interpreter 模式)、状态模式、策略模式、职责链模式(责任链模式)。 注意:不同的书籍上对分类和名称略有差别 七大设计原则 1、单一职责原则【SINGLE RESPONSIBILITY PRINCIPLE】:一个类负责一项职责. 2、里氏替换原则【LISKOV SUBSTITUTION PRINCIPLE】:继承与派生的规则. 3、依赖倒置原则【DEPENDENCE INVERSION PRINCIPLE】:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。即针对接口编程,不要针对实现编程. 4、接口隔离原则【INTERFACE SEGREGATION PRINCIPLE】:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少. 5、迪米特法则【LOW OF DEMETER】:低耦合,高内聚. 6、开闭原则【OPEN CLOSE PRINCIPLE】:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭. 7、组合/聚合复用原则【Composition/Aggregation Reuse Principle(CARP) 】:尽量使用组合和聚合少使用继承的关系来达到复用的原则.
本次学习了以下几种常用的设计模式:
以下附上各种设计模式的跟敲代码部分:
创建型模式:
单例模式---另有一篇文章专门讲单例模式:https://blog.csdn.net/hello_world123456789/article/details/92767498
package com.herbert.singleton;
/**
* @author Herbert
* @create 2019-11-29 10:40
*/
class Singleton {
//饿汉式(静态代码块)
//1。私有化构造
private Singleton(){}
//2。内部创建对象
private static final Singleton INSTANCE;
static{
INSTANCE=new Singleton();
}
//3。提供一个外部调用
public static Singleton getInstance(){
return INSTANCE;
}
}
class Singleton1{
//懒汉式(有线程问题)
private Singleton1(){}
private static Singleton1 instance1;
public static Singleton1 getInstance(){
if(instance1==null){
//可以通过线程休眠,显示线程安全问题
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance1=new Singleton1();
}
return instance1;
}
}
class Singleton2{
//懒汉式(同步锁,解决线程问题),但每次调getInstance()获取实例时都会锁,无论实例是否一存在,效率不高
private Singleton2(){}
private static Singleton2 instance2;
public static synchronized Singleton2 getInstance(){//这里用的是同步方法(synchronized关键字放在方法上)解决线程安全,如果这里用同步代码块方式写,是不解决线程安全问题的
if(instance2==null){
instance2=new Singleton2();
}
return instance2;
}
}
class Singleton3{
//懒汉式(双重检查),解决效率问题,先判断实例是否存在,再锁(锁放在判断之后)
private Singleton3(){}
private static volatile Singleton3 instance3;
public static Singleton3 getInstance(){
if(instance3==null){
synchronized (Singleton2.class){
if(instance3==null){
instance3=new Singleton3();
}
}
}
return instance3;
}
}
class Singleton4{
//静态内部类,也算是懒汉式的一种实现方式。内部类调用是一种懒加载的方式,外部类加载的时候不会去加载内部类,只有当调用内部类的时候才会去加载,无论内部类是否静态
private Singleton4(){}
private static class SingletonInstance{
private static final Singleton4 INSTANCE = new Singleton4();
}
public static Singleton4 getInstance(){
return SingletonInstance.INSTANCE;
}
}
enum Singleton5{
//枚举实现单例
INSTANCE;
}
package com.herbert.singleton;
import org.junit.Test;
/**
* @author Herbert
* @create 2019-11-29 10:46
*/
public class SingletonTest {
@Test
public void test(){
Singleton instance = Singleton.getInstance();
Singleton _instance = Singleton.getInstance();
System.out.println(instance.hashCode());
System.out.println(_instance.hashCode());
System.out.println(instance==_instance);
}
@Test
public void test1(){
Singleton1 instance1 = Singleton1.getInstance();
Singleton1 _instance1 = Singleton1.getInstance();
System.out.println(instance1.hashCode());
System.out.println(_instance1.hashCode());
System.out.println(instance1==_instance1);
}
@Test
public void test2(){
Singleton2 instance2 = Singleton2.getInstance();
Singleton2 _instance2 = Singleton2.getInstance();
System.out.println(instance2.hashCode());
System.out.println(_instance2.hashCode());
System.out.println(instance2==_instance2);
}
@Test
public void test5(){
Singleton5 instance5 = Singleton5.INSTANCE;
Singleton5 _instance5 = Singleton5.INSTANCE;
System.out.println(instance5.hashCode());
System.out.println(_instance5.hashCode());
System.out.println(instance5==_instance5);
}
}
工厂模式
package com.herbert.factory;
/**
* @author Herbert
* @create 2019-12-02 13:09
* 工厂模式1:简单工厂模式
* 缺点:新添一款汽车还是要修改简单工厂类的if判断,违背了设计模式的ocp开闭原则---》修改称工厂方法模式
*/
public class SimpleFactoryDemo {
public static void main(String[] args) {
//简单工厂
SimpleFactory simpleFactory = new SimpleFactory();
Car bwm = simpleFactory.creatCar("BWM");
System.out.println(bwm.name);
}
}
/*
@param name 产品名称
*/
class SimpleFactory {//简单工厂模式
public Car creatCar(String carName) {
if (carName.equals("BWM")) {
return new BWM("宝马");
} else if (carName.equals("Benz")) {
return new Benz("奔驰");
} else {
System.out.println("无法生产该类型汽车");
}
return null;
}
}
class Car {
protected String name;
public Car(String name) {
this.name = name;
}
}
class BWM extends Car {
public BWM(String name) {
super(name);
}
}
class Benz extends Car {
public Benz(String name) {
super(name);
}
}
package com.herbert.factory;
/**
* @author Herbert
* @create 2019-12-02 14:05
*/
public class FactoryMethodDemo {
public static void main(String[] args) {
BWMFactory bwmFactory = new BWMFactory();
Car car = bwmFactory.createCar();
System.out.println(car.name);
}
}
//创建一个父工厂抽象类
abstract class ParentFactory{
abstract Car createCar();
}
//不同型号汽车单独创建工厂类,继承父工厂
/*
如果此时增加产品型号,只需创建一个相应的汽车类继承Car类,然后创建一个单独的型号汽车工厂继承父工厂,不涉及原有代码额更改,不违背ocp原则
*/
class BWMFactory extends ParentFactory{
@Override
Car createCar() {
return new BWM("宝马");
}
}
class BenzFactory extends ParentFactory{
@Override
Car createCar() {
return new Benz("奔驰");
}
}
//工厂方法模式的car相关代码是一样的,car类相关的代码在simpleFactoryDemo文件内
/*class Car {
protected String name;
public Car(String name) {
this.name = name;
}
}
class BWM extends Car {
public BWM(String name) {
super(name);
}
}
class Benz extends Car {
public Benz(String name) {
super(name);
}
}*/
package com.herbert.factory;
/**
* @author Herbert
* @create 2019-12-02 14:26
* 抽象工厂:生产产品族,实际就是工厂方法的父工厂有多个生产功能,eg:生产汽车和生产手机,写法上就是多一个抽象方法
*/
public class AbstractFactoryDemo {
public static void main(String[] args) {
HuaWeiPhoneFactory huaWeiPhoneFactory = new HuaWeiPhoneFactory();
Phone huawei = huaWeiPhoneFactory.createPhone();
System.out.println(huawei.name);
System.out.println("----------------");
IPhonePhoneFactory iPhonePhoneFactory = new IPhonePhoneFactory();
Phone apple = iPhonePhoneFactory.createPhone();
System.out.println(apple.name);
}
}
//这里也可以用接口
/*
需要生产什么单独建一个自工厂,实现功能就可以。如果有新的型号,同理直接添加对应的类及子工厂类即可,不影响ocp原则
*/
abstract class AbstractFactory{
abstract Car createCar();
abstract Phone createPhone();
}
//生产车的子工厂-宝马工厂
class BWMCarFactory extends AbstractFactory{
@Override
Car createCar() {
return new BWM("宝马");
}
@Override
Phone createPhone() {
return null;
}
}
//生产车的子工厂-奔驰工厂
class BenzCarFactory extends AbstractFactory{
@Override
Car createCar() {
return new Benz("奔驰");
}
@Override
Phone createPhone() {
return null;
}
}
//生产手机的子工厂-iPhone工厂
class IPhonePhoneFactory extends AbstractFactory{
@Override
Car createCar() {
return null;
}
@Override
Phone createPhone() {
return new IPhone("苹果");
}
}
//生产手机的子工厂-华为工厂
class HuaWeiPhoneFactory extends AbstractFactory{
@Override
Car createCar() {
return null;
}
@Override
Phone createPhone() {
return new IPhone("华为");
}
}
/*
手机类:iPhone和huawei
*/
class Phone{
protected String name;
public Phone(){}
public Phone(String name) {
this.name = name;
}
}
class IPhone extends Phone{
public IPhone(String name) {
super(name);
}
}
class HuaWei extends Phone{
public HuaWei(String name) {
super(name);
}
}
//工厂方法模式的car相关代码是一样的,car类相关的代码在simpleFactoryDemo文件内
/*class Car {
protected String name;
public Car(String name) {
this.name = name;
}
}
class BWM extends Car {
public BWM(String name) {
super(name);
}
}
class Benz extends Car {
public Benz(String name) {
super(name);
}
}*/
原型模式
package com.herbert.prototype;
import java.io.*;
/**
* @author Herbert
* @create 2019-12-03 13:18
* 原型模式:克隆羊问题---复制10个相同的羊
* 实际应用场景:Spring框架bean的创建,type属性控制type="prototype"
*
* 什么是浅克隆和深克隆?---通俗将,复制对象时,其中的引用数据类型是沿用原来数据,还是重新创建新空间将数据再存一份(hashcode值判断)
* 浅克隆:仅仅复制所克隆的对象,而不复制它所引用的对象。
* 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。
*
* 深克隆:把要复制的对象所引用的对象都复制了一遍。
* 那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。
*
* 很明显二者时间消耗有差距,在不影响的情况下尽量用浅克隆
*/
public class PrototypeDemo {
public static void main(String[] args) throws CloneNotSupportedException {
Wolf friend = new Wolf();
friend.setName("灰太狼");
friend.setAge("10");
Sheep sheep1 = new Sheep("喜洋洋", "10", "白色", friend);
//复制10只羊
System.out.println(sheep1);
System.out.println("-------------以下手动new创建复制对象,属于浅克隆-----------------");
/*
方式1:手动new创建对象,效率低
*/
for (int i = 0; i < 10; i++) {
Sheep sheep = new Sheep(sheep1.getName(), sheep1.getAge(), sheep1.getColor(), sheep1.getFriend());
System.out.println("复制体sheep:" + sheep + ",复制体sheep的hashcode值:" + sheep.hashCode() + ",复制体sheep的引用数据类型hashcode值:" + sheep.getFriend().hashCode());
}
System.out.println("--------------以下属于浅克隆----------------");
/*
方式2:原型模式--浅克隆
Object对象有个clone()方法,实现了对象中各个属性的复制,但它的可见范围是protected的,所以实体类使用克隆的前提是:
① 被克隆对象需要实现Cloneable接口,这是一个标记接口,自身没有方法。
② 覆盖clone()方法,可见性提升为public。
这里要提到一点,默认的clone方法是浅克隆的,但这里为什么要重写?因为默认的clone方法是protected的,需要打开为public
*/
for (int i = 0; i < 10; i++) {
Sheep sheep = (Sheep) sheep1.clone();
System.out.println("复制体sheep:" + sheep + ",复制体sheep的hashcode值:" + sheep.hashCode() + ",复制体sheep的引用数据类型hashcode值:" + sheep.getFriend().hashCode());
}
System.out.println("-----------以下为序列化方式实现深克隆(推荐!!!)-----------------");
/*
方式3:原型模式---深克隆(推荐!!!!)
深克隆---利用序列化和反序列化
① 被克隆对象,及引用类型对象都需要实现Serializable接口,不用实现cloneable接口
*/
try {
for (int i = 0; i < 10; i++) {
//创建流对象
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(sheep1);//被克隆的对象写入内存
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Sheep sheep = (Sheep) ois.readObject();//从内存复制对象
System.out.println("复制体sheep:" + sheep + ",复制体sheep的hashcode值:" + sheep.hashCode() + ",复制体sheep的引用数据类型hashcode值:" + sheep.getFriend().hashCode());
//释放流资源
baos.close();
oos.close();
bais.close();
ois.close();
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("--------------以下重写clone方法,手动分开处理基本数据类型和引用数据类型方式实现深克隆-----------------");
/*
方式3:原型模式---深克隆
深克隆---被克隆对象的类需要重写clone方法,分开处理基本数据类型和引用数据类型
这里我重写以下sheep类,前面写太多有点乱
① 被克隆对象,及引用类型对象都需要实现cloneable接口,以及重写clone方法,不用实现serializable接口
*/
DeepWolf friend1 = new DeepWolf();
friend1.setName("蕉太狼");
friend1.setAge("9");
DeepSheep sheep2 = new DeepSheep("懒洋洋", "10", "白色", friend1);
for (int i = 0; i < 10; i++) {
DeepSheep sheep = (DeepSheep) sheep2.clone();
System.out.println("复制体sheep:" + sheep + ",复制体sheep的hashcode值:" + sheep.hashCode() + ",复制体sheep的引用数据类型hashcode值:" + sheep.getFriend().hashCode());
}
}
}
class DeepSheep implements Cloneable{
private String name;//基本类型
private String age;
private String color;
private DeepWolf friend;//引用类型
public DeepWolf getFriend() {
return friend;
}
public void setFriend(DeepWolf friend) {
this.friend = friend;
}
public DeepSheep() {
}
public DeepSheep(String name, String age, String color, DeepWolf friend) {
this.name = name;
this.age = age;
this.color = color;
this.friend = friend;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
", color='" + color + '\'' +
", friend=" + friend +
'}';
}
@Override
public Object clone() throws CloneNotSupportedException {
Object sheep=null;
sheep = super.clone();//这里完成对基本数据类型和string类型的克隆
//对引用数据类型单独处理
DeepSheep dSheep = (DeepSheep) sheep;
dSheep.friend=(DeepWolf)friend.clone();
return dSheep;
}
}
class DeepWolf implements Cloneable {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Wolf{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Sheep implements Cloneable, Serializable {
private String name;//基本类型
private String age;
private String color;
private Wolf friend;//引用类型
public Wolf getFriend() {
return friend;
}
public void setFriend(Wolf friend) {
this.friend = friend;
}
public Sheep() {
}
public Sheep(String name, String age, String color, Wolf friend) {
this.name = name;
this.age = age;
this.color = color;
this.friend = friend;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
", color='" + color + '\'' +
", friend=" + friend +
'}';
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Wolf implements Serializable {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Wolf{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
建造者模式
package com.herbert.builder;
/**
* @author Herbert
* @create 2019-12-05 10:49
* 建造者模式:以建房子为例子,创造者模式主要涉及以下四个角色
* 1) Product(产品角色): 一个具体的产品对象。
* 2) Builder(抽象建造者): 创建一个 Product 对象的各个部件指定的 接口/抽象类。
* 3) ConcreteBuilder(具体建造者): 实现接口,构建和装配各个部件。
* 4) Director(指挥者): 构建一个使用 Builder 接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。
*
* 工厂模式和创造者模式区别:
* 工厂模式一般都是创建一个产品,注重的是把这个产品创建出来就行,只要创建出来,不关心这个产品的组成部分。从代码上看,工厂模式就是一个方法,用这个方法就能生产出产品。
* 建造者模式也是创建一个产品,但是不仅要把这个产品创建出来,还要关系这个产品的组成细节,组成过程。从代码上看,建造者模式在建造产品时,这个产品有很多方法,建造者模式会根据这些相同方法但是不同执行顺序建造出不同组成细节的产品。
*
* 可以比较两个模式的example代码,一比较就会比较出来,工厂模式关心整体,建造者模式关心细节。
*/
public class BuliderDemo {
public static void main(String[] args) {
//普通房
CommonBuildingBuilder commonBuildingBuilder = new CommonBuildingBuilder();
HouseDirector houseDirector = new HouseDirector(commonBuildingBuilder);
houseDirector.build();
System.out.println("---------------------");
//高楼
HighBuildingBuilder highBuildingBuilder = new HighBuildingBuilder();
//重制建造者
houseDirector.setHouseBuilder(highBuildingBuilder);
houseDirector.build();
}
}
/*
1、建造者模式用于建造产品,其产品类一般都是一个模板(模板设计模式),所以一定会有产品类
*/
//产品类
class House{
private String basic; //地基
private String walls; //墙体
private String roof; //屋顶
public String getBasic() {
return basic;
}
public void setBasic(String basic) {
this.basic = basic;
}
public String getWalls() {
return walls;
}
public void setWalls(String walls) {
this.walls = walls;
}
public String getRoof() {
return roof;
}
public void setRoof(String roof) {
this.roof = roof;
}
}
/*
2、抽象建造者,这个建造者会定义产品的不同部分以及其他产品定义的细节问题,然后根据这些细节建造产品
*/
//抽象创造者
abstract class HouseBuilder{
protected House house = new House();
//将建造的流程写好, 抽象的方法
public abstract void buildBasic();
public abstract void buildWalls();
public abstract void buildRoof();
//建造房子好, 将产品(房子) 返回
public House buildHouse(){
return house;
}
}
/*
3、具体的建造者,在具体的建造者中,一定会有一个产品的对象,通过对这个产品对象的组成部分定义,建造出具体不同细节的产品
*/
//具体创造者---普通房创造者
class CommonBuildingBuilder extends HouseBuilder{
@Override
public void buildBasic() {
System.out.println("普通房子建10m地基");
}
@Override
public void buildWalls() {
System.out.println("普通房子建5m墙体");
}
@Override
public void buildRoof() {
System.out.println("普通房子建屋顶");
}
}
//具体创造者---高楼的创造者
class HighBuildingBuilder extends HouseBuilder {
@Override
public void buildBasic() {
System.out.println("高楼建30m地基");
}
@Override
public void buildWalls() {
System.out.println("高楼建10m墙体");
}
@Override
public void buildRoof() {
System.out.println("高楼建屋顶");
}
}
/*
导演类,这个类就是建造出可能出现的、具有不同细节的产品的建造者的集合,只要在客户端有导演类的实例,并且告诉导演类我要什么样的产品,导演类就会返回这个产品
*/
//指挥者类
class HouseDirector{
protected HouseBuilder houseBuilder;
public HouseDirector(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
//通过setter传入不同房型
public void setHouseBuilder(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
//指挥者处理建房流程
public House build(){
houseBuilder.buildBasic();
houseBuilder.buildWalls();
houseBuilder.buildRoof();
return houseBuilder.buildHouse();
}
}
结构性模式
装饰者模式
package com.herbert.decorator;
/**
* @author Herbert
* @create 2019-12-07 15:40
*
*/
/*
总的抽象类,作为单品coffee和调料的共有父类
*/
abstract class Drink {
private String description;//物品描述,是coffee还是调味品
private float price;//价钱
public String getDescription() {
return description + "-" + price;
}
public void setDescription(String description) {
this.description = description;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
abstract float cost();//计算开销
}
package com.herbert.decorator;
/**
* @author Herbert
* @create 2019-12-07 15:40
* <p>
* 咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡)
*/
//创建一个中间过度类(也可以不要,直接继承drink,各种咖啡添以下cost方法)
public class Coffee extends Drink {
@Override
float cost() {
return super.getPrice();
}
}
class Espresso extends Coffee {
public Espresso() {
super.setDescription("Espresso");
super.setPrice(1.0f);
}
}
class ShortBlack extends Coffee {
public ShortBlack() {
super.setDescription("ShortBlack");
super.setPrice(2.0f);
}
}
class LongBlack extends Coffee {
public LongBlack() {
super.setDescription("LongBlack");
super.setPrice(3.0f);
}
}
class Decaf extends Coffee {
public Decaf() {
super.setDescription("Decaf");
super.setPrice(4.0f);
}
}
package com.herbert.decorator;
/**
* @author Herbert
* @create 2019-12-07 15:56
* <p>
* 调料:Milk、Soy(豆浆)、Chocolate
*/
//装饰者类
public class Decorator extends Drink {
/*
这里是聚合关系。为什么这里要创建一个成员变量drink,而milk中不需要创建呢?
之所以定义一个成员变量,是为了接收创建decorator对象时,传入的drink对象,drink对象在下面cost和description方法中有使用。
像下面的milk中的drink只作为局部变量,不涉及到其他方法中使用,也就是不需要申明一个成员变量用于接收传入的drink对象,这里需要注意下区别。
*/
private Drink obj;
protected Decorator(Drink obj) {
this.obj = obj;
}
@Override
float cost() {
return super.getPrice() + obj.cost();//装饰者(milk)+ 被装饰者(coffee),被装饰着可以是已经被包装过一次的,一种递归处理
}
@Override
public String getDescription() {
return super.getDescription() +" && "+ obj.getDescription();//第二项也是递归
}
}
//具体的decorator,调味料
class Milk extends Decorator {
public Milk(Drink obj) {
super(obj);
this.setDescription("牛奶");
this.setPrice(0.5f);
}
}
class Soy extends Decorator {
public Soy(Drink obj) {
super(obj);
this.setDescription("豆浆");
this.setPrice(1.5f);
}
}
class Chocolate extends Decorator {
public Chocolate(Drink obj) {
super(obj);
this.setDescription("巧克力");
this.setPrice(2.5f);
}
}
package com.herbert.decorator;
/**
* @author Herbert
* @create 2019-12-07 15:36
* 1) 咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡)
* 2) 调料:Milk、Soy(豆浆)、Chocolate
*/
public class DecoratorDemo {
public static void main(String[] args) {
//点一份espresso,加2份milk和1份chocolate
Drink espresso = new Espresso();
printDetail(espresso);
//加第1份奶
espresso = new Milk(espresso);
printDetail(espresso);
//加第2份奶
espresso = new Milk(espresso);
printDetail(espresso);
//加巧克力
espresso = new Chocolate(espresso);
printDetail(espresso);
}
public static void printDetail(Drink drink) {
System.out.println(drink.getDescription());
System.out.println(drink.cost());
System.out.println("-------------");
}
}
代理模式
package com.herbert.proxy;
/**
* @author Herbert
* @create 2019-12-10 09:13
*
* 代理模式:静态代理+动态代理(jdk动态代理/cglib动态代理)
*
* 静态代理:代理对象与目标对象要实现相同的接口,然后通过调用相同的方法来调用目标对象的方法
*
* 动态代理:jdk动态代理-代理对象,不需要实现接口,但目标对象还是实现原接口;
* cglib动态代理-静态代理和JDK代理模式都要求目标对象是实现一个接口,
* 但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候使用cglib动态代理,代理工厂需要实现 MethodInterceptor接口
*
*总结:静态代理---代理类和目标类实现同一接口
* jdk动态代理---目标类实现原接口,代理工厂不需要实现任何接口(适用目标类有实现接口)
* cglib动态代理---目标不需要实现接口,代理工厂需要实现 MethodInterceptor接口,记得导入4个依赖包(适用目标类无实现接口)
*/
/*
静态代理实现
*/
public class ProxyDemo {
public static void main(String[] args) {
TeacherDao target = new TeacherDao();
StaticProxy staticProxy = new StaticProxy(target);
staticProxy.teach();
}
}
/*
接口类
*/
interface ITeacherDao{
void teach();
}
/*
目标类(被代理的类)
*/
class TeacherDao implements ITeacherDao{
@Override
public void teach() {
System.out.println("老师授课中。。。");
}
}
class StaticProxy implements ITeacherDao{
//创建一个目标对象变量-聚合关系
private ITeacherDao target;
public StaticProxy(ITeacherDao target){
this.target=target;
}
@Override
public void teach() {
System.out.println("课前点名。。。");
target.teach();
System.out.println("课后答疑。。。");
}
}
package com.herbert.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author Herbert
* @create 2019-12-10 09:28
* JDK 实现代理只需要使用 newProxyInstance 方法,但是该方法需要接收三个参数,完整的写法是:
* static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
*
* 参数解释:
* 1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
* 2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
* 3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
*/
/*
jdk动态代理
*/
public class JDKProxyDemo {
public static void main(String[] args) {
ITeacherDao1 target = new TeacherDao1();//目标对象
JDkProxyFactory factory = new JDkProxyFactory(target);//代理工厂对象(用于创建代理对象)
ITeacherDao1 jdkProxy = (ITeacherDao1) factory.getJDKProxy();//获得代理对象
jdkProxy.teach();//代理对象调用目标类方法
}
}
/*
接口类
*/
interface ITeacherDao1{
void teach();
}
/*
目标类
*/
class TeacherDao1 implements ITeacherDao1{
@Override
public void teach() {
System.out.println("老师授课中1。。。");
}
}
/*
代理工厂类
*/
class JDkProxyFactory {
//创建一个目标对象变量
private Object target;
//构造器
public JDkProxyFactory(Object target){
this.target=target;
}
//获取代理对象
public Object getJDKProxy(){
Object JDKProxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("目标行为前的操作。。。");
Object invokeVal = method.invoke(target, args);
System.out.println("目标行为后的操作。。。");
return invokeVal;
}
});
return JDKProxy;
}
}
package com.herbert.proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author Herbert
* @create 2019-12-10 10:17
* 工厂类中创建代理对象四步
* public Object getProxyInstance() {
* //1. 创建一个工具类
* Enhancer enhancer = new Enhancer();
* //2. 设置父类
* enhancer.setSuperclass(target.getClass());
* //3. 设置回调函数
* enhancer.setCallback(this);
* //4. 创建子类对象,即代理对象
* return enhancer.create();}
*/
/*
cglib动态代理
*/
public class CglibProxyDemo {
public static void main(String[] args) {
TeacherDao2 target = new TeacherDao2();
CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(target);
TeacherDao2 cglibProxy = (TeacherDao2) cglibProxyFactory.getCglibProxy();
cglibProxy.teach();
}
}
/*
目标类
*/
class TeacherDao2 {
void teach() {
System.out.println("老师授课中。。。");
}
}
/*
工厂类
*/
class CglibProxyFactory implements MethodInterceptor {
//目标类对象-聚合
private Object target;
//构造器
public CglibProxyFactory(Object target) {
this.target = target;
}
/*
* Object proxy:代理对象的引用。不一定每次都会有
* Method method:当前执行的方法
* Object[] args:当前执行方法所需的参数
* MethodProxy methodProxy:当前执行方法的代理对象,一般不用
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("目标行为前的操作。。。");
// Object invokeVal = methodProxy.invokeSuper(proxy, args); //两种调用都可以
Object invokeVal = method.invoke(target,args);
System.out.println("目标行为后的操作。。。");
return invokeVal;
}
public Object getCglibProxy() {
//1. 创建一个工具类
Enhancer enhancer = new Enhancer();
//2. 设置父类
enhancer.setSuperclass(target.getClass());
//3. 设置回调函数
enhancer.setCallback(this);
//4. 创建代理对象
Object cglibProxy = enhancer.create();
return cglibProxy;
}
}
适配器模式
package com.herbert.adapter;
import com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory;
/**
* @author Herbert
* @create 2019-12-05 20:09
* 1) 适配器模式(AdapterPattern)将某个类的接口转换成客户端期望的另一个接口表示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为包装器(Wrapper)
* 2) 适配器模式属于结构型模式
* 3) 主要分为三类:类适配器模式、对象适配器模式、接口适配器模式
*
* 现实中的例子,国标,美标,欧标,其他(充电头)
*/
/*
类适配器实例
基本介绍:Adapter 类,通过继承 src 类,实现 dst 类接口,完成 src->dst 的适配。
*/
public class ClassAdapterDemo {
public static void main(String[] args) {
Phone phone = new Phone();
IVoltage5V iVoltage5V = new VoltageAdapter();
phone.charge(iVoltage5V);
}
}
//被适配的类
class Voltage220V{
//输出220v电压
private int srcV;
public int output220V(){
srcV=220;
System.out.println("源电压="+srcV+"伏");
return srcV;
}
}
//适配接口
interface IVoltage5V{
public int output5V();
}
//适配器类
class VoltageAdapter extends Voltage220V implements IVoltage5V{
@Override
public int output5V() {
//获取220v电压
int srcV = output220V();
//转换成5v电压
int destV=srcV/44;
return destV;
}
}
//手机类
class Phone{
//充电
public void charge(IVoltage5V iVoltage5V){
if(iVoltage5V.output5V()==5){
System.out.println("手机充电电压为5v,正在充电");
}else{
System.out.println("手机充电电压不为5v,无法充电");
}
}
}
package com.herbert.adapter;
/**
* @author Herbert
* @create 2019-12-05 22:21
*/
/*
对象适配器模式
基本思路和类的适配器模式相同,只是将Adapter类作修改,不是继承src类,而是持有src类的实例,以解决
兼容性的问题。 即:持有 src 类,实现 dst 类接口,完成 src->dst 的适配
*/
public class ObjectAdapterDemo {
public static void main(String[] args) {
Phone1 phone1 = new Phone1();
phone1.charge(new VoltageAdapter1(new Voltage220V1()));
}
}
//被适配的类
class Voltage220V1 {
//输出220v电压
private int srcV;
public int output220V() {
srcV = 220;
System.out.println("源电压=" + srcV + "伏");
return srcV;
}
}
//适配接口
interface IVoltage5V1 {
public int output5V();
}
//适配器类
class VoltageAdapter1 implements IVoltage5V1 {
//关联关系-聚合
private Voltage220V1 voltage220V1;
VoltageAdapter1(Voltage220V1 voltage220V1) {
this.voltage220V1 = voltage220V1;
}
@Override
public int output5V() {
//获取220v电压
int srcV = voltage220V1.output220V();
//转换成5v电压
int destV = srcV / 44;
return destV;
}
}
//手机类
class Phone1 {
//充电
public void charge(IVoltage5V1 iVoltage5V1) {
if (iVoltage5V1.output5V() == 5) {
System.out.println("手机充电电压为5v,正在充电");
} else {
System.out.println("手机充电电压不为5v,无法充电");
}
}
}
package com.herbert.adapter;
/**
* @author Herbert
* @create 2019-12-06 10:18
*/
/*
接口适配器模式
*/
public class InterfaceAdapterDemo {
public static void main(String[] args) {
AbsAdapter absAdapter = new AbsAdapter(){
@Override
public void m1() {
System.out.println("重写m1方法");
}
};
absAdapter.m1();
}
}
//接口
interface interface_{
//方法
void m1();
void m2();
void m3();
void m4();
}
//适配器类---用抽象类继承,默认实现
class AbsAdapter implements interface_{
//空实现,谁调用,谁重写,调用哪个,重写哪个原则
@Override
public void m1() {
}
@Override
public void m2() {
}
@Override
public void m3() {
}
@Override
public void m4() {
}
}
行为型模式:
观察者模式
package com.herbert.observer;
import java.util.ArrayList;
/**
* @author Herbert
* @create 2019-12-09 14:53
* <p>
* 1) 观察者模式
* 2) 气象站:Subject
* 3) 第三方网站:Observer
* <p>
* Subject:登记注册、移除和通知
* 1) registerObserver 注册
* 2) removeObserver 移除
* 3) notifyObservers() 通知所有的注册的用户,根据不同需求,可以是更新数据,让用户来取,也可能是实施推送,
* 看具体需求定
*/
public class ObserverDemo {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
//百度
Observer baidu = new Baidu();
//将百度网站观察者注入
weatherData.registerObserver(baidu);
//新浪
Observer sina = new Sina();
//将新浪网站观察者注入
weatherData.registerObserver(sina);
//天气更新
weatherData.setWeatherData("30","80.6","30.4");
}
}
/*
气象站接口,需要一个类实现
*/
interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
interface Observer {
public void update(String temperature, String pressure, String humidity);
}
/*
气象站的实现,包含温度,湿度,气压等参数
*/
class WeatherData implements Subject {
private String temperature;
private String pressure;
private String humidity;
//观察者集合---组合
private ArrayList<Observer> observers;
public WeatherData() {
observers = new ArrayList<>();
}
public String getTemperature() {
return temperature;
}
public void setTemperature(String temperature) {
this.temperature = temperature;
}
public String getPressure() {
return pressure;
}
public void setPressure(String pressure) {
this.pressure = pressure;
}
public String getHumidity() {
return humidity;
}
public void setHumidity(String humidity) {
this.humidity = humidity;
}
void setWeatherData(String temperature, String pressure, String humidity) {
setTemperature(temperature);
setPressure(pressure);
setHumidity(humidity);
//同时发出数据更新的通知
dataChange();
}
/*
气象数据发生更新时发出通知
*/
void dataChange() {
notifyObservers();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers() { //遍历集合,通知各位观察者数据更新
for (int i = 0; i < observers.size(); i++) {
observers.get(i).update(temperature, pressure, humidity);
}
}
}
/*
观察者实现类
*/
class Baidu implements Observer {
private String temperature;
private String pressure;
private String humidity;
@Override
public void update(String temperature, String pressure, String humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
display();
}
//显示当前气象信息
private void display() {
System.out.println("百度为你播报:");
System.out.println("当前温度:" + temperature);
System.out.println("当前气压:" + pressure);
System.out.println("当前湿度:" + humidity);
}
}
class Sina implements Observer {
private String temperature;
private String pressure;
private String humidity;
@Override
public void update(String temperature, String pressure, String humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
display();
}
//显示当前气象信息
private void display() {
System.out.println("新浪为你播报:");
System.out.println("当前温度:" + temperature);
System.out.println("当前气压:" + pressure);
System.out.println("当前湿度:" + humidity);
}
}