学习资料:狂神说Java
设计模式
省去new,帮我们更好的创建对象
饿汉式,DCL懒汉式,深究!
饿汉式:
//饿汉式单例
public class Hungry {
//问题,可能浪费空间
private byte[] data1 = new byte[1 * 1024 * 1024];
private byte[] data2 = new byte[1 * 1024 * 1024];
private byte[] data3 = new byte[1 * 1024 * 1024];
private byte[] data4 = new byte[1 * 1024 * 1024];
//构造函数私有:别人就不能new了
private Hungry() {
}
//一上来就new,加载
private final static Hungry HUNGRY = new Hungry();
public static Hungry getInstance() {
return HUNGRY;
}
}
问题:很可能会浪费内存
懒汉式:(双重检测锁模式懒汉式单例)
//懒汉式单例
public class LazyMan {
private volatile static LazyMan lazyMan;//避免指令重排
//构造器私有
private LazyMan() {
System.out.println(Thread.currentThread().getName() + "Ok");
}
//双重检测锁模式的懒汉式单例,DCL懒汉式
public static LazyMan getInstance() {
if (lazyMan == null) {
synchronized (LazyMan.class) {
if (lazyMan == null) {
lazyMan = new LazyMan();// 不是原子性操作
/**
* 1. 分配内存空间
* 2. 执行构造方法,初始化对象
* 3. 把这个对象指向这个空间
*
* 可能指令重排的现象
* 原来:123
* 如果:132 A线程没问题
* B //此时lazyMan还没有完成构造
*/
}
}
}
return lazyMan;
}
//单线程ok,多线程并发下
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
LazyMan.getInstance();
}).start();
}
}
}
静态内部类:
package 设计模式.单例模式;
//静态内部类
//不安全有反射这个东西
public class Holder {
private Holder(){
}
public static Holder getInstance(){
return InnerClass.HOLDER;
}
public static class InnerClass{
private static final Holder HOLDER = new Holder();
}
}
反射破坏单例:
public static void main(String[] args) throws Exception {
LazyMan lazyMan1 = new LazyMan();
Constructor<LazyMan> constructor = LazyMan.class.getDeclaredConstructor(null);
constructor.setAccessible(true);//无视private
LazyMan lazyMan2 = constructor.newInstance();
System.out.println(lazyMan1==lazyMan2);
}
}
解决:最终解决,源码中枚举类型不能被反射破坏
import java.lang.reflect.Constructor;
//枚举 是什么?本身也是一个类
public enum EnumSingle {
INSTANCE;//默认单例
public EnumSingle getInstance(){
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws Exception {
EnumSingle enumSingle1 = EnumSingle.INSTANCE;
Constructor<EnumSingle> constructor = EnumSingle.class.getDeclaredConstructor(null);
constructor.setAccessible(true);
EnumSingle enumSingle2 = constructor.newInstance();
System.out.println(enumSingle1==enumSingle2);
}
}
编译器骗了我们枚举没有无参构造
枚举没有无参构造的,有有参构造(String,int)
实现了创建者和调用者分离
分类
简单工厂模式
package factory.simple;
public interface Car {
public void name();
}
public class TesLa implements Car {
@Override
public void name() {
System.out.println("特斯拉!");
}
}
---------------------------------------
package edu.xalead.factory.simple;
public class WuLin implements Car {
@Override
public void name() {
System.out.println("五菱宏光!");
}
}
package factory.simple;
//弊端: 增加一个新的产品,需要修改原来的代码(为了满足开闭原则)
public class Consumer {
public static void main(String[] args) {
//之前
// Car wuLin = new WuLin();
// Car tesLa = new TesLa();
//使用工厂创建
Car wuLin = CarFactory.getCar("五菱");
Car tesLa = CarFactory.getCar("特斯拉");
wuLin.name();
tesLa.name();
}
}
package factory.simple;
public class CarFactory {
public static Car getCar(String car){
if(car.equals("五菱")){
return new WuLin();
}else if (car.equals("特斯拉")){
return new TesLa();
}else
return null;
}
}
工厂方法模式
package edu.xalead.factory.method;
public interface Car {
public void name();
}
package edu.xalead.factory.method;
public interface CarFactory {
Car getCar();
}
package edu.xalead.factory.method;
public class TesLa implements Car {
@Override
public void name() {
System.out.println("特斯拉!");
}
}
对应车接口:
package edu.xalead.factory.method;
public class TesLaFactory implements CarFactory {
@Override
public Car getCar() {
return new TesLa();
}
}
--------------------------------------------------------
package edu.xalead.factory.method;
public class WuLin implements Car {
@Override
public void name() {
System.out.println("五菱宏光!");
}
}
对应车接口:
package edu.xalead.factory.method;
public class WuLinFactory implements CarFactory {
@Override
public Car getCar() {
return new WuLin();
}
}
package edu.xalead.factory.method;
public class Consumer {
public static void main(String[] args) {
Car car1 = new WuLinFactory().getCar();
Car car2 = new TesLaFactory().getCar();
car1.name();
car2.name();
}
}
抽象工厂模式
package edu.xalead.factory.abstract1;
//抽象产品工厂
public interface IProductFactory {
//生产手机
IphoneProduct getPhone();
//生产路由器
IRouterProduct getRouter();
}
- 华为工厂,总工厂已经确定需要生产哪些产品了
package edu.xalead.factory.abstract1;
public class HuaweiFactory implements IProductFactory {
@Override
public IphoneProduct getPhone() {
return new HuaweiPhone();
}
@Override
public IRouterProduct getRouter() {
return new HuaweiRouter();
}
}
- 华为产品
//手机
package edu.xalead.factory.abstract1;
public class HuaweiPhone implements IphoneProduct {
@Override
public void start() {
System.out.println("开启华为手机");
}
@Override
public void shutdown() {
System.out.println("关闭华为手机");
}
@Override
public void callup() {
System.out.println("华为手机打电话");
}
@Override
public void sendSMS() {
System.out.println("华为发短信");
}
}
-----------------------------------------------
//路由器
package edu.xalead.factory.abstract1;
public class HuaweiRouter implements IRouterProduct {
@Override
public void start() {
System.out.println("启动华为路由器");
}
@Override
public void shutdown() {
System.out.println("关闭华为路由器");
}
@Override
public void setting() {
System.out.println("设置华为路由器");
}
}
- 小米工厂
package edu.xalead.factory.abstract1;
public class XiaomiFactory implements IProductFactory {
@Override
public IphoneProduct getPhone() {
return new XiaomiPhone();
}
@Override
public IRouterProduct getRouter() {
return new XiaomiRouter();
}
}
- 小米产品
//手机
package edu.xalead.factory.abstract1;
public class XiaomiPhone implements IphoneProduct {
@Override
public void start() {
System.out.println("开启小米手机");
}
@Override
public void shutdown() {
System.out.println("关闭小米手机");
}
@Override
public void callup() {
System.out.println("小米打电话");
}
@Override
public void sendSMS() {
System.out.println("小米发短信");
}
}
//路由器
package edu.xalead.factory.abstract1;
public class XiaomiRouter implements IRouterProduct {
@Override
public void start() {
System.out.println("启动小米路由器");
}
@Override
public void shutdown() {
System.out.println("关闭小米路由器");
}
@Override
public void setting() {
System.out.println("设置小米路由器");
}
}
//产品接口
package edu.xalead.factory.abstract1;
//手机接口
public interface IphoneProduct {
void start();
void shutdown();
void callup();
void sendSMS();
}
------------------------------------
package edu.xalead.factory.abstract1;
//路由器接口
public interface IRouterProduct {
void start();
void shutdown();
void setting();
}
- 客户
package edu.xalead.factory.abstract1;
public class Client {
public static void main(String[] args) {
//小米工厂
XiaomiFactory xiaomiFactory = new XiaomiFactory();
//手机
IphoneProduct phone = xiaomiFactory.getPhone();
phone.start();
phone.callup();
//路由器
IRouterProduct router = xiaomiFactory.getRouter();
router.start();
router.setting();
HuaweiFactory huaweiFactory = new HuaweiFactory();
IphoneProduct phone1 = huaweiFactory.getPhone();
phone.start();
phone.callup();
IRouterProduct router1 = huaweiFactory.getRouter();
router1.start();
router1.setting();
}
}
满足oop七大原则
核心本质
应用场景
提供了一种创建对象的最佳方式
定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建 过程可以创建不同的表示。
主要作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。
用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
例子:
代码实现
建房子的例子,必须要有个指挥
抽象的Builder
package edu.xalead.builder.demo1;
//抽象的建造者:方法
public abstract class Builder {
abstract void builderA();//地基
abstract void builderB();//钢筋框架
abstract void builderC();//铺电线
abstract void builderD();//粉刷
// 经过ABCD四步,就完工了
abstract Product getProduct();
}
产品
package edu.xalead.builder.demo1;
import lombok.Data;
import lombok.ToString;
//产品:房子
@Data
@ToString
public class Product {
private String buildA;
private String buildB;
private String buildC;
private String buildD;
}
具体Builder
package edu.xalead.builder.demo1;
//具体的建造者:工人
public class Worker extends Builder {
private Product product;
//工人创建产品
public Worker(){
product = new Product();
}
@Override
void builderA() {
product.setBuildA("地基");
System.out.println("地基");
}
@Override
void builderB() {
product.setBuildB("钢筋框架");
System.out.println("钢筋框架");
}
@Override
void builderC() {
product.setBuildC("铺设电线");
System.out.println("铺设电线");
}
@Override
void builderD() {
product.setBuildD("粉刷");
System.out.println("粉刷");
}
@Override
Product getProduct() {
return product;
}
}
指挥
package edu.xalead.builder.demo1;
//指挥:核心,指挥一个工程的构建
public class Director {
//指挥工人按照顺序建造房子
public Product build(Builder builder){
builder.builderA();
builder.builderB();
builder.builderC();
builder.builderD();
return builder.getProduct();
}
}
测试:
package edu.xalead.builder.demo1;
public class TestBuild {
public static void main(String[] args) {
//指挥
Director director = new Director();
//指挥具体的工人
Product build = director.build(new Worker());
System.out.println(build.toString());
}
}
买东西,我们用户可以选除了套餐外的其它搭配
抽象Builder
package edu.xalead.builder.demo2;
//建造者
public abstract class Builder {
abstract Builder builderA(String msg);//汉堡
abstract Builder builderB(String msg);//可乐
abstract Builder builderC(String msg);//薯条
abstract Builder builderD(String msg);//甜品
// 经过ABCD四步,套餐完成
abstract Product getProduct();
}
产品
package edu.xalead.builder.demo2;
import lombok.Data;
import lombok.ToString;
//产品:套餐
@Data
@ToString
public class Product {
private String BuildA = "汉堡";
private String BuildB = "可乐";
private String BuildC = "薯条";
private String BuildD = "甜品";
}
具体Builder
package edu.xalead.builder.demo2;
//具体的建造者
public class Worker extends Builder {
private Product product;
public Worker(){
product = new Product();
}
@Override
Builder builderA(String msg) {
product.setBuildA(msg);
return this;
}
@Override
Builder builderB(String msg) {
product.setBuildB(msg);
return this;
}
@Override
Builder builderC(String msg) {
product.setBuildC(msg);
return this;
}
@Override
Builder builderD(String msg) {
product.setBuildD(msg);
return this;
}
@Override
Product getProduct() {
return product;
}
}
测试
package edu.xalead.builder.demo2;
public class Test {
public static void main(String[] args) {
//服务员
Worker worker = new Worker();
//链式编程:在原来基础上可以自由组合了,如果不组合就用默认的
Product product = worker.builderA("全家桶")
.builderB("雪碧")
.builderC("薯片")
.getProduct();
System.out.println(product.toString());
}
}
优点:
缺点:
应用场景:
建造者与抽象工厂模式的比较:
主要是克隆:
clone()
实现cloneable接口
clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法
重写clone()方法
clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。
分浅拷贝和深拷贝:
浅拷贝:
拷贝对象和原始对象的引用类型引用同一个对象
深拷贝:
拷贝对象和原始对象的引用类型引用不同对象。
package edu.xalead.prototype.demo1;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.Date;
/**
* 1. 实现一个接口
* 2. 重写一个方法
*/
//Video
@Data
@NoArgsConstructor
@ToString
public class Video implements Cloneable{
private String name;
private Date createTime;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Video(String name, Date createTime) {
this.name = name;
this.createTime = createTime;
}
}
客户端:
package edu.xalead.prototype.demo1;
import java.util.Date;
// 客户端: 克隆
public class Client {
// 浅拷贝,公用同一个数据date
public static void main(String[] args) throws CloneNotSupportedException {
//原型对象
Date date = new Date();
Video v1 = new Video("网站",date);
System.out.println("v1=>"+v1);
System.out.println("v1=>hash:"+v1.hashCode());
//v1 克隆出 v2
Video v2 = (Video) v1.clone();
System.out.println("v2=>"+v2);
System.out.println("v2=>hash:"+v2.hashCode());
v2.setName("克隆网站");
System.out.println(v2);
}
}
深拷贝例子:
package edu.xalead.prototype.demo2;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.Date;
/**
* 1. 实现一个接口
* 2. 重写一个方法
*/
//Video
@Data
@NoArgsConstructor
@ToString
public class Video implements Cloneable{
private String name;
private Date createTime;
@Override
protected Object clone() throws CloneNotSupportedException {
Object clone = super.clone();
//实现深克隆
Video v = (Video) clone;
//将这个对象的属性也克隆一份
v.createTime = (Date) this.createTime.clone();
return v;
}
public Video(String name, Date createTime) {
this.name = name;
this.createTime = createTime;
}
}
客户端:
package edu.xalead.prototype.demo2;
import java.util.Date;
// 客户端: 克隆
/**
* Spring Bean :单例模式,原型模式创建
*
* 原型模式 + 工厂 ==》 new <=> 原型模式
*/
public class Client {
// 深拷贝
public static void main(String[] args) throws CloneNotSupportedException {
//原型对象
Date date = new Date();
Video v1 = new Video("网站",date);
Video v2 = (Video) v1.clone();
System.out.println("v1=>"+v1);
System.out.println("v2=>"+v2);
//
date.setTime(152645789);
System.out.println("--------------------------");
System.out.println("v1=>"+v1);
System.out.println("v2=>"+v2);
}
}
作用: 从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能- -起工作的
那些类可以在一起工作!
角色分析
对象适配器优点
◆一个对象适配器可以把多个不同的适配者适配到同-一个目标
◆可以适配一-个适配者的子类,由于适配器和适配者之间是关联关系,根据“里氏代换原则”,适配者
的子类也可通过该适配器进行适配。
类适配器缺点
对于Java、 C#等不支持多重类继承的语言,一次最多只能适配一个适配者类,不能同时适配多个适配者;
在Java、 C#等语言中,类适配器模式中的目标抽象类只能为接口,不能为类,其使用有一定的局限性。
适用场景
代码
当我们需要用网线上网的时候,但电脑是薄的无法插网线
网线:
package edu.xalead.adapter;
//要被适配的类:比如网线
public class Adaptered {
public void request(){
System.out.println("网线上网");
}
}
适配器:
//抽象接口
package edu.xalead.adapter;
//转换器的抽象实现
public interface NetToUsb {
//作用处理请求,把网线插到适配器上适配器插到usb接口
void handleRequest();
}
------------------------------------
package edu.xalead.adapter;
/**
* 1. 继承(类适配器,单继承)
*/
//真正的适配器,需要连接USB,连接网线
public class Adapter extends Adaptered implements NetToUsb {
@Override
public void handleRequest() {
super.request();//可以上网了
}
}
-------------------------------------
package edu.xalead.adapter;
/**
* 2. 组合(对象适配器,常用)
*/
//真正的适配器,需要连接USB,连接网线
public class Adapter2 implements NetToUsb {
private Adaptered adaptered;//网线组合进来了
public Adapter2(Adaptered adaptered) {
this.adaptered = adaptered;
}
@Override
public void handleRequest() {
adaptered.request();//可以上网了
}
}
电脑连网:
package edu.xalead.adapter;
//客户端类:想上网,插不上网线
public class Computer {
public void net(NetToUsb adapter){
//上网但插不上网线,找一个转接头
adapter.handleRequest();
}
public static void main(String[] args) {
//电脑,适配器,网线
Computer computer = new Computer();
Adaptered adaptered = new Adaptered();//网线
// Adapter adapter = new Adapter();
Adapter2 adapter = new Adapter2(adaptered);//
computer.net(adapter);
}
}
有两个以上变化的维度:比如联想,苹果,戴尔,他们都有台式机,笔记本,平板
好处分析:
桥接模式偶尔类似于多继承方案,但是多继承方案违背了类的单一职责原则,复用性比较差,类的个数也非常多,桥接模式是比多继承方案更好的解决方法。极大的减少了子类的个数,从而降低管理和维护的成本
桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。符合开闭原则,就像一座桥,可以把两个变化的维度连接起来!
劣势分析:
最佳实践:
场景:
AWT中的Peer架构
JDBC驱动程序也是桥接模式的应用之一。
思考?桥接模式+适配器模式
SpringAOP底层
分类:
角色分析:
上代码:
抽象角色:
package edu.xalead.proxy.demo1;
//抽象的接口,出租房子这件事
public interface Rent {
void rent();
}
真实角色:
package edu.xalead.proxy.demo1;
//房东,真实角色
public class Hoster implements Rent {
@Override
public void rent() {
System.out.println("本房东有房子出租");
}
}
代理角色:
package edu.xalead.proxy.demo1;
public class ProxyRent implements Rent {
private Hoster hoster;
public ProxyRent(Hoster hoster) {
this.hoster = hoster;
}
@Override
public void rent() {
seeHouse();
hoster.rent();
hetong();
}
//还可以做一些其它的事
public void seeHouse(){
System.out.println("中介带你看房子");
}
public void hetong(){
System.out.println("签合同");
}
}
客户:
package edu.xalead.proxy.demo1;
//客户来租房了
public class Client {
public static void main(String[] args) {
//房东出租房子
Hoster hoster = new Hoster();
//代理角色,中介帮房东租房子,但是呢,代理角色还有些附属操作
ProxyRent proxyRent = new ProxyRent(hoster);
//你看不到房东,直接找中介租房子
proxyRent.rent();
}
}
代理模式的好处: .
可以使真实角色的操作更加纯粹!不用去关注- -些公共的业务
公共也就就交给代理角色!实现了业务的分工!
公共业务发生扩展的时候,方便集中管理!
缺点:
我们在这里使用基于接口的动态代理
我们在这里了解两个类:
上代码:
package edu.xalead.proxy.demo4active;
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加了一个用户");
}
@Override
public void del() {
System.out.println("删除了一个用户");
}
@Override
public void update() {
System.out.println("更新了一个用户");
}
@Override
public void query() {
System.out.println("查询出一个用户");
}
}
package edu.xalead.proxy.demo4active;
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加了一个用户");
}
@Override
public void del() {
System.out.println("删除了一个用户");
}
@Override
public void update() {
System.out.println("更新了一个用户");
}
@Override
public void query() {
System.out.println("查询出一个用户");
}
}
package edu.xalead.proxy.demo4active;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//这个类,自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//Proxy,生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
//InvocationHandler
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质就是利用反射实现
Object result = method.invoke(target, args);
return result;
}
}
package edu.xalead.proxy.demo4active;
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//生成代理角色
ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler();
invocationHandler.setTarget(userService);
UserService proxy = (UserService)invocationHandler.getProxy();//动态生成代理类
proxy.add();
}
}
好处,一个动态代理类,可以代理多个类,只要是实现了同一个接口即可。
后续会继续更新的,
欢迎访问我的个人博客交流:http://www.ayjup.cn