一、XML实现数据库查询
xml:可扩展标记语言,前些年主要用于网络间传输数据,近些年主要用于作为各种第三方框架的配置文件使用
XML配置
db.xml
<?xml version="1.0" encoding="UTF-8"?>
<dataSource>
<driverClassName>com.mysql.jdbc.Driver</driverClassName>
<url>jdbc:mysql://localhost:3306/woniumall?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC</url>
<user>root</user>
<password>123456</password>
</dataSource>
sql.xml
<?xml version="1.0" encoding="UTF-8"?>
<sql>
<!-- 表示是一个查询语句 excuteQuery()
resultType:指定将查询出来的结果封装成哪种类型的对象
-->
<select resultType="com.woniuxy.entity.User">
select * from mall_user
</select>
</sql>
SQL类
package com.woniuxy.entity;
import lombok.Data;
@Data
public class Sql {
private String resultType;
private String sql;
}
User实体类
package com.woniuxy.entity;
import java.util.Date;
import lombok.Data;
@Data
public class User {
private int id; // id
private String account; // 账号
private String password; // 密码
private String email; // 邮箱
private String avatar; // 头像
private int score; // 积分
private Date regtime; // 注册时间
private String status; // 状态
}
DBTest测试类
public class DBTest {
public static void main(String[] args) throws Exception {
String driverClassName = null;
String url = null;
String user = null;
String password = null;
// 通过自己写的方法获取迭代器
Iterator<?> iterator = getIterator("db.xml");
while (iterator.hasNext()) {
Element child = (Element) iterator.next();
// 获取标签名和text
String name = child.getName();
String value = child.getText();
// 判断标签的名字
if (name.equals("driverClassName")) {
driverClassName = value;
} else if (name.equals("url")) {
url = value;
} else if (name.equals("user")) {
user = value;
} else if (name.equals("password")) {
password = value;
}
}
// 加载驱动、创建连接、创建查询、执行SQL、解析数据封装成指定类型的数据
Class.forName(driverClassName);
Connection connection = DriverManager.getConnection(url, user, password);
Statement statement = connection.createStatement();
// 读取sql.xml文件中的SQL语句
Sql sql = getSql();
// 执行SQL,封装成指定类型的数据
List<Object> data = JdbcUtil.getData(sql.getResultType(), statement.executeQuery(sql.getSql()));
for (Object object : data) {
System.out.println(object);
}
statement.close();
connection.close();
}
/**
* 根据XML文件名获取迭代器
*
* @param fileName
* @return
* @throws DocumentException
* @throws MalformedURLException
*/
private static Iterator<?> getIterator(String fileName) throws DocumentException, MalformedURLException {
// 获取当前项目的路径
String projectPath = System.getProperty("user.dir");
// 文件路径
String path = projectPath + File.separator + "src" + File.separator + fileName;
// 创建文件解析器、获取document对象
Document document = new SAXReader().read(new File(path));
// 获取根标签
Element root = document.getRootElement();
// 遍历子标签
Iterator<?> iterator = root.elementIterator();
return iterator;
}
/**
* 解析sql.xml 返回SQL语句和resultType
*
* @throws Exception
*
*/
public static Sql getSql() throws Exception {
Iterator<?> iterator = getIterator("sql.xml");
Sql obj = new Sql();
while (iterator.hasNext()) {
Element select = (Element) iterator.next();
// 获取属性
String resultType = select.attributeValue("resultType");
String sql = select.getTextTrim();// 去掉空白字符
obj.setResultType(resultType);
obj.setSql(sql);
}
return obj;
}
}
二、单例模式
2.1 饱汉模式(加或不加sychronized)
package com.woniuxy.designer.single;
/**
* 饱汉模式:
* 1.私有化所有的构造方法
* 2.提供一个静态、公开的方法,用来返回一个当前类型的对象
* 3.提供一个私有、静态的指向本类对象的属性,并赋值为null
* @author 99285
*
*/
class Sun {
// 3.私有静态属性
private static Sun instance = null;
// 1.私有化构造方法
private Sun() {
}
// 2.公开方法
public static Sun getInstance() {
if(instance == null) {
instance = new Sun();
}
return instance;
}
// 加同步锁的写法
// public static sychronized Sun getInstance() {
// if(instance == null) {
// instance = new Sun();
// }
// return instance;
// }
}
弊端:在多线程中,可能会创建出不同的实例,需要在getInstance()方法前加sychronized,但此时效率不够高
**
2.2 饥汉模式
package com.woniuxy.designer.single;
/**
* 饥汉模式
* 1.私有化构造方法
* 2.提供一个静态、公开的方法获取该类型的对象
* 3.提供一个静态、私有的指向当前类型对象的属性,并在此时调用构造方法创建对象
* @author 99285
*
*/
class Moon{
// 3.私有属性
private static Moon instance = new Moon();
// 1.私有化构造器
private Moon() {
}
// 2.公开方法,返回当前类型的对象
public static Moon getInstance() {
return instance;
}
}
弊端:如果在一个大环境下使用了过多的饿汉单例,则会生产出过多的实例对象,无论你是否要使用它们
2.3 饱汉模式双重锁模式
package com.woniuxy.designer.single;
/**
* 饱汉模式的双重锁模式,提高效率
*
* @author 99285
*
*/
class Sun2 {
// 3.私有静态属性
private static Sun2 sun2 = null;
// 1.私有化构造方法
private Sun2() {
}
// 2.公开方法
public static Sun2 getInstance() {
if(sun2 == null) {
synchronized(Sun2.class){
if(sun2 == null){
sun2 = new Sun2();
}
}
}
return sun2;
}
}
优点:**进行双重判断,当已经创建过实例对象后就无需加锁,提高效率。也是一种推荐使用的方式
缺点:sun2 = new Sun2() 不是原子性操作,分为三步:
1.分配内存空间
2. 执行构造方法,初始化对象
3.把这个对象指向这个空间
所以在多线程中可能造成还未完成构造就进入下一个线程
解决方法:在私有属性前加上volatile
volatile详解:https://www.cnblogs.com/zhengbin/p/5654805.html#_label0
优化后的双重锁模式**
package com.woniuxy.designer.single;
/**
* 饱汉模式的双重锁模式,提高效率
*
* @author 99285
*
*/
class Sun2 {
// 3.私有静态属性
private volatile static Sun2 sun2 = null;
// 1.私有化构造方法
private Sun2() {
}
// 2.公开方法
public static Sun2 getInstance() {
if(sun2 == null) {
synchronized(Sun2.class){
if(sun2 == null){
sun2 = new Sun2(); // 不是原子性操作
/* 分为三步
* 1.分配内存空间
* 2. 执行构造方法,初始化对象
* 3.把这个对象指向这个空间
* 所以在多线程中可能造成还未完成构造就进入下一个线程
* 解决方法:在私有属性前加上volatile
*/
}
}
}
return sun2;
}
}
2.4 利用线程测试
package com.woniuxy.designer.single;
public class Test {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
// 饱汉存在线程安全问题,需要在getInstance方法上添加synchronized
System.out.println(Sun.getInstance());
// 饥汉无线程安全问题
System.out.println(Moon.getInstance());
}
}).start();
}
}
}
测试结果:其中,Sun.getInstance() 在加同步锁前会产生不同的实例对象,加了后不会发生
**
2.5 饱汉模式、饥汉模式和双重锁模式的对比
1、饥汉模式
是线程安全的,因为实例对象在类加载过程中就会被创建,在getInstance()方法中只是直接返回对象引用。
好处:简单明了,无需关注线程安全问题。
缺点:如果在一个大环境下使用了过多的饿汉单例,则会生产出过多的实例对象,无论你是否要使用他们。
2、饱汉模式
不是线程安全的,因为是在需要的时候才会产生实例对象,生产之前会判断对象引用是否为空,这里,如果多个线程同时进入判断,就会生成多个实例对象,这是不符合单例的思想的。所以饱汉模式为了保证线程安全,就用synchronized关键字标识了方法。
好处:延时加载,用的时候才会生产对象。
缺点:需要保证同步,付出效率的代价。
3、双重锁模式
是饱汉模式的优化,进行双重判断,当已经创建过实例对象后就无需加锁,提高效率。也是一种推荐使用的方式
2.6 对双重锁单例模式进行破坏
记住:单例模式可能会被反射破坏,创建出不同实例对象,反射无法破坏枚举的单例模式(底层代码)
**
举例:
package com.woniuxy.designer.single;
import java.lang.reflect.Constructor;
public class Sun2 {
// 3.私有静态属性
private volatile static Sun2 sun2 = null;
// 1.私有化构造方法
private Sun2() {
}
// 2.公开方法
public static Sun2 getInstance() {
if (sun2 == null) {
synchronized (Sun2.class) {
if (sun2 == null) {
sun2 = new Sun2();
}
}
}
return sun2;
}
// 反射破坏单例模式
public static void main(String[] args) throws Exception {
Sun2 instance1 = Sun2.getInstance();
Constructor<Sun2> declaredConstructor = Sun2.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Sun2 instance2 = declaredConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
}
}
运行结果:
明显不是一个对象,说明单例模式被反射破坏了
具体后续补救操作见:https://www.bilibili.com/video/BV1K54y197iS 10分45秒后
三、装饰器模式
在不修改源代码的情况下增强一个类的功能
package com.woniuxy.designer.decorator;
/**
* 装饰器模式:在不修改源代码的情况下增强一个类的功能
* 1.公共的接口
* 2.被增强功能的类必须实现该接口
* 3.提供一个抽象的增强类
* 4.创建增强功能的类,该类必须继承至上面的抽象类
*
*
* @author 99285
*
*/
// 1.接口
interface Gift{
public void look();
}
// 2.具体要送的礼物
class Cup implements Gift{
@Override
public void look() {
System.out.println("普通杯子");
}
}
// 3.装饰器抽象类
abstract class Decorator implements Gift{
// 拥有一个公共接口的属性
public Gift gift;
public Decorator(Gift gift) {
super();
this.gift = gift;
}
}
// 4.装饰器类:用于增强原有类的功能
class Box extends Decorator{
public Box(Gift gift) {
super(gift);
}
@Override
public void look() {
// 新添加的功能
System.out.println("一个非常漂亮的盒子");
// 执行原有的功能
gift.look();
}
}
//装饰器
class LoveBox extends Decorator{
public LoveBox(Gift gift) {
super(gift);
}
@Override
public void look() {
System.out.println("这人是否对我有意思");
gift.look();
}
}
class LvBox extends Decorator{
public LvBox(Gift gift) {
super(gift);
}
@Override
public void look() {
System.out.println("这人真有钱");
gift.look();
}
}
public class Test {
public static void main(String[] args) {
// 1.原有的
// Cup cup = new Cup();
// 2.装饰器
// LvBox lv = new LvBox(cup);
// LoveBox loveBox = new LoveBox(lv);
// Gift gift = new Box(loveBox);
// 类似IO字符流
Gift gift = new Box(new LoveBox(new LvBox(new Cup())));
// 3.执行公共
gift.look();
}
}
四、工厂模式
作用:实现了创建者和调用者的分离
核心本质:
1、实例化对象不使用new,使用工厂方法替代
2、将选择实现类,创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。
三种工厂模式:
1、简单工厂模式
2、工厂方法模式
3、抽线工厂模式
简单工厂:就是用来创建各种类型的对象
package com.woniuxy.designer.factory;
/**
* 简单工厂:就是用来创建各种类型的对象
* 1.抽象父类:所有能够生产对象的父类
* 2.一堆的各种类
* 3.提供一个工厂类,用于创建各种类型的对象
* @author 99285
*
*/
// 1.抽象父类,交通工具类
abstract class TrafficTools{
public String name;
public TrafficTools(String name) {
super();
this.name = name;
}
}
// 2.各种继承抽象父类的实现类
class Car extends TrafficTools{
public Car(String name) {
super(name);
}
}
class Bus extends TrafficTools{
public Bus(String name) {
super(name);
}
}
class Moto extends TrafficTools{
public Moto(String name) {
super(name);
}
}
// 3.工厂
class TrafficToolsFactory{
public static final String TYPE_CAR = "car";
public static final String TYPE_BUS = "bus";
public static final String TYPE_MOTO = "moto";
public TrafficTools make(String type) {
if(type.equals(TYPE_CAR)) {
return new Car("奔驰");
}else if(type.equals(TYPE_BUS)) {
return new Bus("宇通");
}else if(type.equals(TYPE_MOTO)) {
return new Moto("本田");
}
return null;
}
}
public class Test {
public static void main(String[] args) {
TrafficToolsFactory factory = new TrafficToolsFactory();
TrafficTools tools = factory.make(TrafficToolsFactory.TYPE_MOTO);
System.out.println(tools);
}
}
五、建造者模式
建造者模式:简化创建对象的流程
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
主要作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象
类似于:将对象的创建封装成一个方法
package com.woniuxy.designer.builder;
/**
* 建造者模式:简化创建对象的流程
* 1.需要创建对象类
* 2.建造者
* @author 99285
*
*/
class Head{
}
class Body{
}
class Hand{
}
class Foot{
}
class Robot{
public Head head;
public Body body;
public Hand hand;
public Foot foot;
public Robot(Head head, Body body, Hand hand, Foot foot) {
super();
this.head = head;
this.body = body;
this.hand = hand;
this.foot = foot;
}
}
// 建造者
class RobotBuilder{
public Robot build() {
Head head = new Head();
Body body = new Body();
Hand hand = new Hand();
Foot foot = new Foot();
Robot robot = new Robot(head, body, hand, foot);
return robot;
}
}
public class Test {
public static void main(String[] args) {
Robot robot = new RobotBuilder().build();
}
}
六、适配器模式
6.1 类适配器
局限性:因为用了继承,无法用在final修饰的类上,此时需要使用对象适配器
package com.woniuxy.designer.adapter;
/**
* 类适配器
* 1.需要一个公共的接口:是用户想要的
* 2.实际中现有的功能类
*
* @author 99285
*
*/
// 用户想要的
interface Port {
// 点烟
public void cigarette();
// 充电
public void charging();
}
// 现有的功能类
class CigaretteLighter {
// 点烟
public void cigarette() {
System.out.println("点烟功能");
}
}
// 适配器(转换器)
class Adapter extends CigaretteLighter implements Port{
@Override
public void charging() {
System.out.println("给手机充电");
}
}
public class ClassAdapter {
public static void main(String[] args) {
Port port = new Adapter();
port.cigarette();
port.charging();
}
}
6.2 对象适配器
package com.woniuxy.designer.adapter;
/**
* 对象适配器:在被扩展类是final时使用
* @author 99285
*
*/
//用户想要的
interface Port2 {
// 点烟
public void cigarette();
// 充电
public void charging();
}
//现有的功能类
final class CigaretteLighter2 {
// 点烟
public void cigarette() {
System.out.println("点烟功能");
}
}
// 适配器
class Adapter2 implements Port2{
public CigaretteLighter2 cigaretteLighter;
public Adapter2(CigaretteLighter2 cigaretteLighter) {
super();
this.cigaretteLighter = cigaretteLighter;
}
@Override
public void cigarette() {
// 调用原有功能
cigaretteLighter.cigarette();
}
@Override
public void charging() {
System.out.println("给手机充电");
}
}
public class ObjectAdapter {
public static void main(String[] args) {
Port2 port2 = new Adapter2(new CigaretteLighter2());
port2.cigarette();
port2.charging();
}
}
6.3 缺省适配器
package com.woniuxy.designer.adapter;
/*
* 鲁智深:花和尚
*
* 和尚:戒烟、戒酒、戒色、戒杀生、吃斋、念佛、不打诳语
*
*/
interface 和尚{
public void 吃斋();
public void 戒酒();
public void 戒杀生();
}
class 鲁智深 extends 花和尚{
public void 喝酒() {
}
public void 吃肉() {
}
public void 杀生() {
}
@Override
public void 戒酒(){
}
}
class 花和尚 implements 和尚{
@Override
public void 吃斋() {}//功能缺省
@Override
public void 戒酒() {}
@Override
public void 戒杀生() {}
}
public class DefaultAdapter {
public static void main(String[] args) {
和尚 hs = new 鲁智深();
hs.戒酒();
}
}