七大设计原则
开闭原则、依赖倒置原则、单一职责原则、接口隔离原则、迪米特法则(最少知道原则)、里氏替换原则、合成 (组合)、聚合复用原则
开闭原则
定义: 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。用抽象构建框架,用实现扩展细节
优点: 提高软件系统的可复用性及可维护性
代码示栗:
package com.openclose;
public interface ICourse {
Integer getId();
String getName();
Double getPrice();
}
package com.openclose;
public class JavaCourse implements ICourse{
private Integer id;
private String name;
private Double price;
public JavaCourse(Integer id, String name, Double price) {
this.id = id;
this.name = name;
this.price = price;
}
public Integer getId() {
return this.id;
}
public String getName() {
return this.name;
}
public Double getPrice() {
return this.price;
}
}
package com.openclose;
public class JavaDiscountCourse extends JavaCourse {
public JavaDiscountCourse(Integer id, String name, Double price) {
super(id, name, price);
}
public Double getDiscountPrice(){
return super.getPrice() * 0.6;
}
}
package com.openclose;
/**
* Test
*/
public class OpenCloseTest {
public static void main(String[] args) {
ICourse iCourse = new JavaDiscountCourse(10086,"Java架构",11800D);
JavaDiscountCourse discountCourse = (JavaDiscountCourse)iCourse;
System.out.println("ID:" + discountCourse.getId() +
"\n猪肉标题:《" + discountCourse.getName() + "》" +
"\n原价:" + discountCourse.getPrice() +
"\n售价:" + discountCourse.getDiscountPrice());
}
}
// #输出内容:
//ID:10086
//猪肉标题:《Java架构》
//原价:11800.0
//售价:7080.0
依赖倒置原则
定义: 高层模块不应该依赖低层模块,二者都应该依赖其抽象,抽象不应该依赖细节;细节应该依赖抽象;针对接口编程,不要针对实现编程;
优点: 可以减少类间的耦合性、提高系统稳定性,提高代码可读性和可维护性,可降低修改程序所造成的风险
代码示栗:
package com.dependencyinversion;
/**
* Test
*/
public class DipTest {
public static void main(String[] args) {
//===== V1 ========
// Tom tom = new Tom();
// tom.studyJavaCourse();
// tom.studyPythonCourse();
// tom.studyAICourse();
//===== V2 ========
// Tom tom = new Tom();
// tom.study(new JavaCourse());
// tom.study(new PythonCourse());
//===== V3 ========
// Tom tom = new Tom(new JavaCourse());
// tom.study();
//===== V4 ========
Tom tom = new Tom();
tom.setiCourse(new JavaCourse());
tom.study();
}
}
package com.dependencyinversion;
public class Tom {
// public void studyJavaCourse(){
// System.out.println("Tom正在学习Java课程");
// }
//
// public void studyPythonCourse(){
// System.out.println("Tom正在学习Python课程");
// }
//
// public void studyAICourse(){
// System.out.println("Tom正在学习AI课程");
// }
// public void study(ICourse course){
// course.study();
// }
private ICourse iCourse;
// public Tom(ICourse iCourse) {
// this.iCourse = iCourse;
// }
public void study(){
iCourse.study();
}
public void setiCourse(ICourse iCourse) {
this.iCourse = iCourse;
}
}
package com.dependencyinversion;
public interface ICourse {
void study();
}
package com.dependencyinversion;
public class JavaCourse implements ICourse {
public void study() {
System.out.println("Tom正在学习Java课程");
}
}
package com.gupaoedu.vip.design.principle.dependencyinversion;
public class PythonCourse implements ICourse {
public void study() {
System.out.println("Tom正在学习Python课程");
}
}
单一职责原则
定义: 不要存在多于一个导致类变更的原因。一个类、接口、方法只负责一项职责
优点: 降低类的复杂度; 提高类的可读性; 提高系统的可维护性; 降低变更引起的风险;
代码示栗:
- simple文件夹
package com.simple;
public class Course {
public void study(String courseName){
if("直播课".equals(courseName)){
System.out.println("不能快进");
}else{
System.out.println("可以任意的来回播放");
}
}
}
package com.simple;
public class LiveCourse {
public void study(String courseName){
System.out.println("不能快进");
}
}
package com.simple;
public class ReplayCourse {
public void study(String courseName){
System.out.println("可以任意的来回播放");
}
}
- interfaced文件夹
package com.interfaced;
public interface ICourse {
String getCourseName();
byte[] getCourseVideo();
void studyCourse();
void refundCourse();
}
package com.interfaced;
public interface ICourseInfo {
String getCourseName();
byte[] getCourseVideo();
}
package com.interfaced;
public interface ICourseManager {
void studyCourse();
void refundCourse();
}
package com.interfaced;
public class CourseImpl implements ICourseInfo,ICourseManager {
public String getCourseName() {
return null;
}
public byte[] getCourseVideo() {
return new byte[0];
}
public void studyCourse() {
}
public void refundCourse() {
}
}
- method文件夹
package com.method;
public class Method {
private void modifyUserInfo(String userName,String address){
userName = "Tom";
address = "Changsha";
}
private void modifyUserInfo(String userName,String ... fileds){
}
private void modifyUserInfo(String userName,String address,boolean bool){
if(bool){
}else{
}
}
private void modifyUserName(String userName){
}
private void modifyAddress(String address){
}
}
接口隔离原则
定义: 用多个专门的接口,而不是使用单一的总接口,客户端不应该依赖它不需要的接口
注意: 一个类对应一个类的依赖应该建立在最小的接口上。建立单一接口,不要建立庞大臃肿的解耦; 尽量细化接口,接口中的方法尽量少;注意适度原则,一定要适度;
优点: 符合我们常说的高内聚、低耦合的设计思想。从而使得类具有很好的可读性,可扩展性和可维护性。
代码示栗:
- simple文件夹
package com.simple;
public interface IAnimal {
void eat();
void fly();
void swim();
}
package com.simple;
public class Dog implements IAnimal {
public void eat() {
}
public void fly() {
}
public void swim() {
}
}
package com.simple;
public class Bird implements IAnimal {
public void eat() {
}
public void fly() {
}
public void swim() {
}
}
- segregation文件夹
package com.segregation;
public interface IEatAminal {
void eat();
}
package com.segregation;
public interface IFlyAminal {
void fly();
}
package com.segregation;
public interface ISwimAminal {
void swin();
}
package com.segregation;
public class Bird implements IEatAminal,IFlyAminal {
public void eat() {
}
public void fly() {
}
}
package com.segregation;
public class Dog implements ISwimAminal,IEatAminal {
public void eat() {
}
public void swin() {
}
}
迪米特法则(最少知道原则)
定义: 一个对象应该对其他对象保持最少的了解。又叫最少知道原则,尽量降低类与类之间的耦合;
强调只和朋友交流,不和陌生人说话;
朋友: 出现在成员变量、方法的输入、输出参数中的类成为成员朋友类,而出现在方法体内部的类不属于朋友类
优点: 降低类之间的耦合
代码示栗:
package com.demeter;
/**
* Test
*/
public class LodTest {
public static void main(String[] args) {
TeamLeader teamLeader = new TeamLeader();
Employee employee = new Employee();
teamLeader.commandCheckNumber(employee);
}
}
// #输出内容:
//目前已发布的课程数量为:20
package com.demeter;
public class TeamLeader {
public void commandCheckNumber(Employee employee){
employee.checkNumberOfCourses();
}
}
package com.demeter;
import java.util.ArrayList;
import java.util.List;
public class Employee {
public void checkNumberOfCourses(){
List<Course> courseList = new ArrayList<Course>();
for (int i = 0; i < 20; i ++){
courseList.add(new Course());
}
System.out.println("目前已发布的课程数量为:" + courseList.size());
}
}
package com.demeter;
public class Course {
}
里氏替换原则
定义: 如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都替换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。
定义扩展:
一个软件实体如果适用一个父类的话,那一定适用于其子类所有引用父类的地方必须能透明地使用其子类的对象,子类对象能够替换父类对象,而程序逻辑不变。
引申意义:
子类可以扩展父类的功能,但不能改变父类原有的功能。
含义1:
子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
含义2:
子类中可以增加自己特有的方法。
含义3:
当子类的方法重载父类的方法时,方法的前置条件(即方法的输入、入参)要比父类方法的输入参数更宽松。
含义4:
当子类的方法实现父类的方法时(重写、重载或实现抽象方法)方法的后置条件(即方法的输出、返回值)要比父类更严格或相等。
优点1:
约束继承泛滥,开闭原则的一种体现。
优点2:
加强程序的健壮性,同时变更时也可以做到非常好的兼容性提高程序的维护性,扩展性。降低需求变更时引入的风险。
代码示栗:
- simple文件夹
package com.simple;
/**
* SimpleTest
*/
public class SimpleTest {
public static void resize(Rectangle rectangle){
while (rectangle.getWidth() >= rectangle.getHeight()){
rectangle.setHeight(rectangle.getHeight() + 1);
System.out.println("Width:" +rectangle.getWidth() +",Height:" + rectangle.getHeight());
}
System.out.println("Resize End,Width:" +rectangle.getWidth() +",Height:" + rectangle.getHeight());
}
// public static void main(String[] args) {
// Rectangle rectangle = new Rectangle();
// rectangle.setWidth(20);
// rectangle.setHeight(10);
// resize(rectangle);
// }
// # 输出内容:
//Width:20,Height:11
//Width:20,Height:12
//Width:20,Height:13
//Width:20,Height:14
//Width:20,Height:15
//Width:20,Height:16
//Width:20,Height:17
//Width:20,Height:18
//Width:20,Height:19
//Width:20,Height:20
//Width:20,Height:21
//Resize End,Width:20,Height:21
public static void main(String[] args) {
Square square = new Square();
square.setLength(10);
resize(square);
}
// # 输出内容:死循环
//Width:206805,Height:206805
//Width:206806,Height:206806
...
}
package com.simple;
public class Rectangle {
private long height;
private long width;
public long getHeight() {
return height;
}
public void setHeight(long height) {
this.height = height;
}
public long getWidth() {
return width;
}
public void setWidth(long width) {
this.width = width;
}
}
package com.simple;
public class Square extends Rectangle {
private long length;
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
@Override
public long getHeight() {
return getLength();
}
@Override
public void setHeight(long height) {
setLength(height);
}
@Override
public long getWidth() {
return getLength();
}
@Override
public void setWidth(long width) {
setLength(width);
}
}
- liskovsutiution文件夹
package com.liskovsutiution;
public interface QuadRangle {
long getWidth();
long getHeight();
}
package com.liskovsutiution;
public class Rectangle implements QuadRangle {
private long height;
private long width;
public long getHeight() {
return height;
}
public void setHeight(long height) {
this.height = height;
}
public long getWidth() {
return width;
}
public void setWidth(long width) {
this.width = width;
}
}
package com.liskovsutiution;
public class Square implements QuadRangle {
private long length;
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
public long getWidth() {
return length;
}
public long getHeight() {
return length;
}
}
package com.liskovsutiution;
/**
* IspTest
*/
public class IspTest {
public static void resize(Rectangle rectangle){
while (rectangle.getWidth() >= rectangle.getHeight()){
rectangle.setHeight(rectangle.getHeight() + 1);
System.out.println("Width:" +rectangle.getWidth() +",Height:" + rectangle.getHeight());
}
System.out.println("Resize End,Width:" +rectangle.getWidth() +",Height:" + rectangle.getHeight());
}
// public static void main(String[] args) {
// Rectangle rectangle = new Rectangle();
// rectangle.setWidth(20);
// rectangle.setHeight(10);
// resize(rectangle);
// }
//# 输出内容:
//Width:20,Height:11
//Width:20,Height:12
//Width:20,Height:13
//Width:20,Height:14
//Width:20,Height:15
//Width:20,Height:16
//Width:20,Height:17
//Width:20,Height:18
//Width:20,Height:19
//Width:20,Height:20
//Width:20,Height:21
//Resize End,Width:20,Height:21
public static void resize1(QuadRangle rectangle){
while (rectangle.getWidth() >= rectangle.getHeight()){
// rectangle.setLength(rectangle.getHeight() + 1);
System.out.println("Width:" +rectangle.getWidth() +",Height:" + rectangle.getHeight());
}
System.out.println("Resize End,Width:" +rectangle.getWidth() +",Height:" + rectangle.getHeight());
}
public static void main(String[] args) {
Square square = new Square();
square.setLength(10);
resize1(square);
}
//# 输出内容: 死循环
//Width:10,Height:10
//Width:10,Height:10
}
- methodparam文件夹
package com.methodparam;
import java.util.HashMap;
/**
* MethodParamTest
*/
public class MethodParamTest {
public static void main(String[] args) {
Base child = new Child();
HashMap hashMap = new HashMap();
child.method(hashMap);
}
//# 输出内容:(子类重写父类方法@Override 执行子类HashMap)
//父类执行
//执行子类HashMap入参方法
}
package com.methodparam;
import java.util.HashMap;
public class Base {
public void method(HashMap map){
System.out.println("父类执行");
}
}
package com.methodparam;
import java.util.HashMap;
import java.util.Map;
public class Child extends Base {
@Override
public void method(HashMap map) {
System.out.println("执行子类HashMap入参方法");
}
public void method(Map map){
System.out.println("执行子类Map入参方法");
}
}
- methodreturn文件夹
package com.methodreturn;
/**
* MethodReturnTest
*/
public class MethodReturnTest {
public static void main(String[] args) {
Base child = new Child();
System.out.println(child.method());
}
//# 输出内容:
//执行子类的method
//{msg=子类method}
}
package com.methodreturn;
import java.util.Map;
public abstract class Base {
public abstract Map method();
}
package com.methodreturn;
import java.util.HashMap;
import java.util.Map;
public class Child extends Base {
@Override
public HashMap method() {
HashMap hashMap = new HashMap();
System.out.println("执行子类的method");
hashMap.put("msg","子类method");
return hashMap;
}
}
合成 (组合)、聚合复用原则
定义: 尽量使用对象组合、聚合、而不是继承关系达到软件复用的目的聚合has-a和组合contains-a
优点: 可以使系统更加灵活,降低类与类之间的耦合度个类的变化对其他类造成的影响相对较少。
何时使用合成/聚合、继承
聚合has-a、组合contains-a、继承is-a
代码示栗:
package com.compositereuse;
/**
* CopTest
*/
public class CopTest {
public static void main(String[] args) {
ProductDao productDao = new ProductDao();
productDao.setConnection(new MySQLConnection());
productDao.addProduct();
}
//# 输出内容:
//获取MySQL数据连接获得数据库连接
}
package com.compositereuse;
public class ProductDao {
private DBConnection dbConnection;
public void setConnection(DBConnection dbConnection){
this.dbConnection = dbConnection;
}
public void addProduct(){
String conn = dbConnection.getConnection();
System.out.println(conn + "获得数据库连接");
}
}
package com.compositereuse;
public abstract class DBConnection {
public abstract String getConnection();
// getConnection{
// return "获取MySQL数据连接";
// }
// public String getOracleConntion(){}
}
package com.compositereuse;
public class MyOracleConnection extends DBConnection {
public String getConnection() {
return "获取Oracle数据连接";
}
}
package com.compositereuse;
public class MySQLConnection extends DBConnection {
public String getConnection() {
return "获取MySQL数据连接";
}
}
设计模式
创建型模式(简单工厂模式、工厂方法模式、抽象工厂模式、单例模式、原型模式、建造者模式)
结构型模式(代理模式、适配器模式、桥接模式、享元模式、组合模式)
行为型模式(委派模式、模板方法模式、策略模式、责任链模式)
创建型模式
简单工厂模式(Simple Factory Pattern)
简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品类的实例。
属于创建型模式,但它不属于GOF23种设计模式
-
简单工厂适用场景
工厂类负责创建的对象较少。
客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心。 -
简单工厂的优点
只需传入一个正确的参数,就可以获取你所需要的对象无须知道其创建的细节。 -
简单工厂的缺点
工厂类的职责相对过重,增加新的产品时需要修改工厂类的判断逻辑违背开闭原则。
不易于扩展过于复杂的产品结构。
代码示栗:
- simplefactory文件夹
package com.simplefactory;
import com.factory.ICourse;
import com.factory.JavaCourse;
/**
* 小作坊式的简单工厂模型
*/
public class SimpleFactoryTest {
public static void main(String[] args) {
// ICourse course = new JavaCourse();
// course.record();
// ICourseFactory factory = new ICourseFactory();
// ICourse course = factory.create("com.gupaoedu.vip.pattern.factory.JavaCourse");
// course.record();
CourseFactory factory = new CourseFactory();
ICourse course = factory.create(JavaCourse.class);
course.record();
}
}
package com.simplefactory;
import com.factory.ICourse;
public class CourseFactory {
// public ICourse create(String name){
// if("java".equals(name)){
// return new JavaCourse();
// }else if("python".equals(name)){
// return new PythonCourse();
// }else {
// return null;
// }
// }
// public ICourse create(String className){
// try {
// if (!(null == className || "".equals(className))) {
// return (ICourse) Class.forName(className).newInstance();
// }
//
// }catch (Exception e){
// e.printStackTrace();
// }
// return null;
// }
// 小作坊简单工厂(反射改造)
public ICourse create(Class<? extends ICourse> clazz){
try {
if (null != clazz) {
return clazz.newInstance();
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
- factory文件夹
package com.factory;
public interface ICourse {
/**
* 录制视频
* @return
*/
void record();
}
package com.factory;
public class JavaCourse implements ICourse {
public void record() {
System.out.println("录制Java课程");
}
}
package com.factory;
public class PythonCourse implements ICourse {
public void record() {
System.out.println("录制Python课程");
}
}
工厂方法模式(Fatory Method Pattern)
工厂方法模式(Fatory Method Pattern) 是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。
属于创建型设计模式
-
工厂方法模式适用场景
创建对象需要大量重复的代码。
客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。一个类通过其子类来指定创建哪个对象。 -
工厂方法模式的优点
用户只需关心所需产品对应的工厂,无须关心创建细节。
加入新产品符合开闭原则,提高了系统的可扩展性。 -
工厂方法模式的缺点
类的个数容易过多,增加了代码结构的复杂度。
增加了系统的抽象性和理解难度。
代码示栗:
- factorymethod文件夹
package com.factorymethod;
import com.factory.ICourse;
/**
* FactoryMethodTest
*/
public class FactoryMethodTest {
public static void main(String[] args) {
ICourseFactory factory = new PythonCourseFactory();
ICourse course = factory.create();
course.record();
factory = new JavaCourseFactory();
course = factory.create();
course.record();
}
}
package com.factorymethod;
import com.factory.ICourse;
/**
* 工厂模型
*/
public interface ICourseFactory {
ICourse create();
}
package com.factorymethod;
import com.factory.ICourse;
import com.factory.PythonCourse;
public class PythonCourseFactory implements ICourseFactory {
public ICourse create() {
return new PythonCourse();
}
}
package com.factorymethod;
import com.factory.ICourse;
import com.factory.JavaCourse;
public class JavaCourseFactory implements ICourseFactory {
public ICourse create() {
return new JavaCourse();
}
}
- factory文件夹
package com.factory;
public interface ICourse {
/**
* 录制视频
* @return
*/
void record();
}
package com.factory;
public class PythonCourse implements ICourse {
public void record() {
System.out.println("录制Python课程");
}
}
package com.factory;
public class JavaCourse implements ICourse {
public void record() {
System.out.println("录制Java课程");
}
}
抽象工厂模式(Abastract Factory Pattern)
抽象工厂模式(Abastract Factory Pattern)是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。
属于创建型设计模式
-
抽象工厂模式的适用场景
客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。
强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。
提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
产品族:一些列的相关的产品,整合到一起有关联性产品等级:同一个继承体系 -
抽象工厂模式的优点
具体产品在应用层代码隔离,无须关心创建细节
将一个系列的产品族统一到一起创建。 -
抽象工厂模式的缺点
规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。
增加了系统的抽象性和理解难度。
代码示栗:
- abstractfactory文件夹
package com.abstractfactory;
/**
* AbstractFactoryTest
*/
public class AbstractFactoryTest {
public static void main(String[] args) {
JavaCourseFactory factory = new JavaCourseFactory();
factory.createNote().edit();
factory.createVideo().record();
}
}
package com.abstractfactory;
import com.factory.INote;
import com.factory.IVideo;
/**
* 抽象工厂是用户的主入口
* 在Spring中应用得最为广泛的一种设计模式
* 易于扩展
*/
public abstract class CourseFactory {
public void init(){
System.out.println("初始化基础数据");
}
protected abstract INote createNote();
protected abstract IVideo createVideo();
}
package com.abstractfactory;
import com.factory.INote;
import com.factory.IVideo;
import com.factory.JavaNote;
import com.factory.JavaVideo;
public class JavaCourseFactory extends CourseFactory {
public INote createNote() {
super.init();
return new JavaNote();
}
public IVideo createVideo() {
super.init();
return new JavaVideo();
}
}
package com.abstractfactory;
import com.factory.INote;
import com.factory.IVideo;
import com.factory.PythonNote;
import com.factory.PythonVideo;
public class PythonCourseFactory extends CourseFactory {
public INote createNote() {
super.init();
return new PythonNote();
}
public IVideo createVideo() {
super.init();
return new PythonVideo();
}
}
- factory文件夹
package com.factory;
/**
* 上课笔记
*/
public interface INote {
void edit();
}
package com.factory;
/**
* Java笔记
*/
public class JavaNote implements INote {
public void edit() {
System.out.println("编写Java笔记");
}
}
package com.factory;
/**
* Python笔记
*/
public class PythonNote implements INote {
public void edit() {
System.out.println("编写Python笔记");
}
}
package com.factory;
/**
* 录播视频
*/
public interface IVideo {
void record();
}
package com.factory;
public class JavaVideo implements IVideo {
public void record() {
System.out.println("录制Java视频");
}
}
package com.factory;
public class PythonVideo implements IVideo {
public void record() {
System.out.println("录制Python视频");
}
}
package com.factory;
public interface ICourse {
/**
* 录制视频
* @return
*/
void record();
}
package com.factory;
public class JavaCourse implements ICourse {
public void record() {
System.out.println("录制Java课程");
}
}
package com.factory;
public class PythonCourse implements ICourse {
public void record() {
System.out.println("录制Python课程");
}
}
单例模式(Singleton Pattern)
单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。
隐藏其所有的构造方法。
属于创建型模式。
-
单例模式的适用场景
确保任何情况下都绝对只有一个实例。 -
##饿汉式单例
在单例类首次加载时就创建实例。 -
##懒汉式单例
被外部类调用时才创建实例。 -
##注册式单例
将每一个实例都缓存到统一的容器中,使用唯一标识获取实例。 -
##ThreadLocal单例
保证线程内部的全局唯一,且天生线程安全。 -
单例模式的优点
在内存中只有一个实例,减少了内存开销。
可以避免对资源的多重占用。
设置全局访问点,严格控制访问。 -
单例模式的缺点
没有接口,扩展困难。
如果要扩展单例对象,只有修改代码,没有其他途径。 -
单例模式的知识重点总结
1、私有化构造器
2、保证线程安全
3、延迟加载
4、防止序列化和反序列化破坏单例
5、防御反射攻击单例
饿汉式单例
在单例类首次加载时就创建实例
代码示栗:
- hungry文件夹
package com.hungry;
/**
* # 饿汉式单例
* 优点:执行效率高,性能高,没有任何的锁
* 缺点:某些情况下,可能会造成内存浪费
*/
public class HungrySingleton {
private static final HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton(){}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
package com.hungry;
public class HungryStaticSingleton {
//先静态后动态
//先上,后下
//先属性后方法
private static final HungryStaticSingleton hungrySingleton;
//装个B
static {
hungrySingleton = new HungryStaticSingleton();
}
private HungryStaticSingleton(){}
public static HungryStaticSingleton getInstance(){
return hungrySingleton;
}
}
懒汉式单例
被外部类调用时才创建实例
代码示栗:
- lazy文件夹
package com.lazy;
/**
* 优点:节省了内存,线程安全
* 缺点:性能低
*/
public class LazySimpleSingletion {
private static LazySimpleSingletion instance;
private LazySimpleSingletion(){}
public synchronized static LazySimpleSingletion getInstance(){
if(instance == null){
instance = new LazySimpleSingletion();
}
return instance;
}
}
package com.test;
import com.lazy.LazySimpleSingletion;
public class ExectorThread implements Runnable {
public void run() {
LazySimpleSingletion instance = LazySimpleSingletion.getInstance();
System.out.println(Thread.currentThread().getName() + ":" + instance);
}
}
package com.test;
/**
* LazySimpleSingletonTest
*/
public class LazySimpleSingletonTest {
public static void main(String[] args) {
Thread t1 = new Thread(new ExectorThread());
Thread t2 = new Thread(new ExectorThread());
t1.start();
t2.start();
System.out.println("End");
// # 输出内容:
// End LazySimpleSingletion.class
// Thread-0:com.lazy.LazySimpleSingletion@3cb7bd5
// Thread-1:com.lazy.LazySimpleSingletion@3cb7bd5
}
package com.lazy;
/**
* 优点:性能高了,线程安全了
* 缺点:可读性难度加大,不够优雅
*/
public class LazyDoubleCheckSingleton {
private volatile static LazyDoubleCheckSingleton instance;
private LazyDoubleCheckSingleton(){}
public static LazyDoubleCheckSingleton getInstance(){
//检查是否要阻塞
if (instance == null) {
synchronized (LazyDoubleCheckSingleton.class) {
//检查是否要重新创建实例
if (instance == null) {
instance = new LazyDoubleCheckSingleton();
//指令重排序的问题
}
}
}
return instance;
}
}
package com.test;
import com.lazy.LazyDoubleCheckSingleton;
public class ExectorThread implements Runnable {
public void run() {
LazyDoubleCheckSingleton instance1 = LazyDoubleCheckSingleton.getInstance();
System.out.println(Thread.currentThread().getName() + ":" + instance1);
}
}
package com.est;
/**
* LazySimpleSingletonTest
*/
public class LazySimpleSingletonTest {
public static void main(String[] args) {
Thread t1 = new Thread(new ExectorThread());
Thread t2 = new Thread(new ExectorThread());
t1.start();
t2.start();
System.out.println("End");
// # 输出内容:
// End LazyDoubleCheckSingleton.class
// Thread-1:com.lazy.LazyDoubleCheckSingleton@b853eab
// Thread-0:com.lazy.LazyDoubleCheckSingleton@b853eab
}
}
package com.lazy;
/*
ClassPath : LazyStaticInnerClassSingleton.class
LazyStaticInnerClassSingleton$LazyHolder.class
优点:写法优雅,利用了Java本身语法特点,性能高,避免了内存浪费,不能被反射破坏
缺点:不优雅
*/
public class LazyStaticInnerClassSingleton {
// 能够给反射破坏
//private LazyStaticInnerClassSingleton(){}
// 防止反射破坏
private LazyStaticInnerClassSingleton(){
if(LazyHolder.INSTANCE != null){
throw new RuntimeException("不允许非法访问");
}
}
public static LazyStaticInnerClassSingleton getInstance(){
return LazyHolder.INSTANCE;
}
private static class LazyHolder{
private static final LazyStaticInnerClassSingleton INSTANCE = new LazyStaticInnerClassSingleton();
}
}
package com.test;
import com.lazy.LazyStaticInnerClassSingleton;
import java.lang.reflect.Constructor;
public class ReflectTest {
public static void main(String[] args) {
try {
LazyStaticInnerClassSingleton instance = LazyStaticInnerClassSingleton.getInstance();
Class<?> clazz = LazyStaticInnerClassSingleton.class;
Constructor c = clazz.getDeclaredConstructor(null);
c.setAccessible(true);
Object instance1 = c.newInstance();
Object instance2 = c.newInstance();
System.out.println(instance1);
System.out.println(instance2);
System.out.println(instance1 == instance2);
// Enum
}catch (Exception e){
e.printStackTrace();
}
}
// # 输出内容:
// Caused by: java.lang.RuntimeException: 不允许非法访问
// at com.lazy.LazyStaticInnerClassSingleton.<init>(LazyStaticInnerClassSingleton.java:17)
// ... 5 more
}
注册式单例
将每一个实例都缓存到统一的容器中,使用唯一标识获取实例。
- 防止序列化和反序列化破坏单例
- 通过 JDK 源码分析 虽然增加readResolve()方法返回实例解决了单例模式被破坏的问题,
- 但是实际上实例化了两次,只不过新创建的对象没有被返回而已。如果创建对象的动作发生频率加快,
- 就意味着内存分配开销也会随之增大,注册式单例模式解决了此问题
代码示栗:
package com.seriable;
import java.io.Serializable;
public class SeriableSingleton implements Serializable {
//序列化
//把内存中对象的状态转换为字节码的形式
//把字节码通过IO输出流,写到磁盘上
//永久保存下来,持久化
//反序列化
//将持久化的字节码内容,通过IO输入流读到内存中来
//转化成一个Java对象
public final static SeriableSingleton INSTANCE = new SeriableSingleton();
private SeriableSingleton(){}
public static SeriableSingleton getInstance(){
return INSTANCE;
}
/**
* 防止序列化和反序列化破坏单例
* 通过 JDK 源码分析 虽然增加readResolve()方法返回实例解决了单例模式被破坏的问题,
* 但是实际上实例化了两次,只不过新创建的对象没有被返回而已。如果创建对象的动作发生频率加快,
* 就意味着内存分配开销也会随之增大,注册式单例模式解决了此问题
* @return
*/
private Object readResolve(){ return INSTANCE;}
}
package com.test;
import com.seriable.SeriableSingleton;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SeriableSingletonTest {
public static void main(String[] args) {
SeriableSingleton s1 = null;
SeriableSingleton s2 = SeriableSingleton.getInstance();
FileOutputStream fos = null;
try {
fos = new FileOutputStream("SeriableSingleton.obj");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s2);
oos.flush();
oos.close();
FileInputStream fis = new FileInputStream("SeriableSingleton.obj");
ObjectInputStream ois = new ObjectInputStream(fis);
s1 = (SeriableSingleton)ois.readObject();
ois.close();
System.out.println(s1);
System.out.println(s2);
System.out.println(s1 == s2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
- Java反编译工具Jad (下载地址: https://varaneckas.com/jad/) , 解压后
枚举式单例模式在静态代码块中就给INSTANCE进行了赋值,是饿汉式单例模式的实现。
package com.register;
public enum EnumSingleton {
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumSingleton getInstance(){return INSTANCE;}
}
package com.test;
import com.register.EnumSingleton;
import java.lang.reflect.Constructor;
public class EnumSingletonTest {
public static void main(String[] args) {
EnumSingleton instance = EnumSingleton.getInstance();
instance.setData(new Object());
try {
Class clazz = EnumSingleton.class;
Constructor c = clazz.getDeclaredConstructor(String.class,int.class);
c.setAccessible(true);
// System.out.println(c);
Object o = c.newInstance();
// System.out.println(o);
}catch (Exception e){
e.printStackTrace();
}
}
// # 输出内容:error
// java.lang.IllegalArgumentException: Cannot reflectively create enum objects
// at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
// at com.test.EnumSingletonTest.main(EnumSingletonTest.java:19)
}
- 容器式单例模式适用于需要大量创建单例对象的场景,便于管理。但它是非线程安全的。
package com.register;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ContainerSingleton {
private ContainerSingleton(){}
private static Map<String,Object> ioc = new ConcurrentHashMap<String, Object>();
public static Object getInstance(String className){
Object instance = null;
if(!ioc.containsKey(className)){
try {
instance = Class.forName(className).newInstance();
ioc.put(className, instance);
}catch (Exception e){
e.printStackTrace();
}
return instance;
}else{
return ioc.get(className);
}
}
}
package com.test;
import com.register.ContainerSingleton;
public class ContainerSingletonTest {
public static void main(String[] args) {
Object instance1 = ContainerSingleton.getInstance("com.gupaoedu.vip.pattern.singleton.test.Pojo");
Object instance2 = ContainerSingleton.getInstance("com.gupaoedu.vip.pattern.singleton.test.Pojo");
System.out.println(instance1 == instance2);
}
}
package com.test;
public class Pojo {
}
ThreadLocal单例
保证线程内部的全局唯一,且天生线程安全
-
ThreadLocal不能保证其创建的对象是全局唯一的 ,但是能保证在单个线程中是唯一的 ,天生是线程安全的。
-
在主线程中无论调用多少次,获取到的实例都是同一个,都在两个子线程中分别获取到了不同的实例。那么ThreadLocal是如何实现这样的效果的呢?我们知道, 单例模式为了达到线程安全的目的,会给方法上锁,以时间换空间。ThreadLocal 将所有的对象全部放在ThreadLocalMap中,为每个线程都提供一个对象,实际上是以空间换时间来实现线程隔离的。
代码示栗:
package com.threadlocal;
public class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> threadLocaLInstance =
new ThreadLocal<ThreadLocalSingleton>(){
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};
private ThreadLocalSingleton(){}
public static ThreadLocalSingleton getInstance(){
return threadLocaLInstance.get();
}
}
package com.test;
import com.threadlocal.ThreadLocalSingleton;
public class ExectorThread implements Runnable {
public void run() {
ThreadLocalSingleton instance = ThreadLocalSingleton.getInstance();
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(Thread.currentThread().getName() + ":" + instance);
}
}
package com.test;
import com.threadlocal.ThreadLocalSingleton;
/**
* ThreadLocalSingletonTest
*/
public class ThreadLocalSingletonTest {
public static void main(String[] args) {
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
System.out.println(ThreadLocalSingleton.getInstance());
Thread t1 = new Thread(new ExectorThread());
Thread t2 = new Thread(new ExectorThread());
t1.start();
t2.start();
System.out.println("End");
// 输出内容:
//com.threadlocal.ThreadLocalSingleton@3caeaf62
//com.threadlocal.ThreadLocalSingleton@3caeaf62
//com.threadlocal.ThreadLocalSingleton@3caeaf62
//End
//com.threadlocal.ThreadLocalSingleton@d2a0537
//Thread-1:com.threadlocal.ThreadLocalSingleton@d2a0537
//com.threadlocal.ThreadLocalSingleton@3c9c242e
//Thread-0:com.threadlocal.ThreadLocalSingleton@3c9c242e
}
}
原型模式(Prototype Pattern)
原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
调用者不需要知道任何创建细节,不调用构造函数。
属于创建型模式
-
原型模式的适用场景
1、类初始化消耗资源较多。
2、new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)。
3、构造函数比较复杂。
4、循环体中生产大量对象时。 -
##浅克隆
-
##深克隆
-
原型模式的优点
性能优良,Java自带的原型模式是基于内存二进制流的铂贝,比直接new一个对象性能上提升了许多。
可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份可〕并将其状态保存起来,简化了创建过程。 -
原型模式的缺点
必须配备克隆(或者可铂贝)方法
当对已有类进行改造的时候,需要修改代码,违反了开闭原则。
深铂贝、浅拷贝需要运用得当
浅克隆
代码示栗:
- demo文件夹
package com.demo;
import lombok.Data;
@Data
public class ExamPaper{
private String examinationPaperId;//试卷主键
private String leavTime;//剩余时间
private String organizationId;//单位主键
private String id;//考试主键
private String examRoomId;//考场主键
private String userId;//用户主键
private String specialtyCode;//专业代码
private String postionCode;//报考岗位
private String gradeCode;//报考等级
private String examStartTime;//考试开始时间
private String examEndTime;//考试结束时间
private String singleSelectionImpCount;//单选选题重要数量
private String multiSelectionImpCount;//多选题重要数量
private String judgementImpCount;//判断题重要数量
private String examTime;//考试时长
private String fullScore;//总分
private String passScore;//及格分
private String userName;//学员姓名
private String score;//考试得分
private String resut;//是否及格
private String singleOkCount;//单选题答对数量
private String multiOkCount;//多选题答对数量
private String judgementOkCount;//判断题答对数量
public ExamPaper copy(){
ExamPaper examPaper = new ExamPaper();
//剩余时间
examPaper.setLeavTime(this.getLeavTime());
//单位主键
examPaper.setOrganizationId(this.getOrganizationId());
//考试主键
examPaper.setId(this.getId());
//用户主键
examPaper.setUserId(this.getUserId());
//专业
examPaper.setSpecialtyCode(this.getSpecialtyCode());
//岗位
examPaper.setPostionCode(this.getPostionCode());
//等级
examPaper.setGradeCode(this.getGradeCode());
//考试开始时间
examPaper.setExamStartTime(this.getExamStartTime());
//考试结束时间
examPaper.setExamEndTime(this.getExamEndTime());
//单选题重要数量
examPaper.setSingleSelectionImpCount(this.getSingleSelectionImpCount());
//多选题重要数量
examPaper.setMultiSelectionImpCount(this.getMultiSelectionImpCount());
//判断题重要数量
examPaper.setJudgementImpCount(this.getJudgementImpCount());
//考试时间
examPaper.setExamTime(this.getExamTime());
//总分
examPaper.setFullScore(this.getFullScore());
//及格分
examPaper.setPassScore(this.getPassScore());
//学员姓名
examPaper.setUserName(this.getUserName());
//分数
examPaper.setScore(this.getScore());
//单选答对数量
examPaper.setSingleOkCount(this.getSingleOkCount());
//多选答对数量
examPaper.setMultiOkCount(this.getMultiOkCount());
//判断答对数量
examPaper.setJudgementOkCount(this.getJudgementOkCount());
return examPaper;
}
@Override
public String toString() {
return "ExamPaper{" +
"examinationPaperId='" + examinationPaperId + '\'' +
", leavTime='" + leavTime + '\'' +
", organizationId='" + organizationId + '\'' +
", id='" + id + '\'' +
", examRoomId='" + examRoomId + '\'' +
", userId='" + userId + '\'' +
", specialtyCode='" + specialtyCode + '\'' +
", postionCode='" + postionCode + '\'' +
", gradeCode='" + gradeCode + '\'' +
", examStartTime='" + examStartTime + '\'' +
", examEndTime='" + examEndTime + '\'' +
", singleSelectionImpCount='" + singleSelectionImpCount + '\'' +
", multiSelectionImpCount='" + multiSelectionImpCount + '\'' +
", judgementImpCount='" + judgementImpCount + '\'' +
", examTime='" + examTime + '\'' +
", fullScore='" + fullScore + '\'' +
", passScore='" + passScore + '\'' +
", userName='" + userName + '\'' +
", score='" + score + '\'' +
", resut='" + resut + '\'' +
", singleOkCount='" + singleOkCount + '\'' +
", multiOkCount='" + multiOkCount + '\'' +
", judgementOkCount='" + judgementOkCount + '\'' +
'}';
}
}
package com.demo;
import java.lang.reflect.Field;
/**
* BeanUtils.copy()
*/
public class BeanUtils {
public static Object copy(Object protorype) {
Class clazz = protorype.getClass();
Object returnValue = null;
try {
returnValue = clazz.newInstance();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
field.set(returnValue, field.get(protorype));
}
}catch (Exception e){
e.printStackTrace();
}
return returnValue;
}
}
package com.demo;
/**
* demoClient-Test
*/
public class Client {
public static void main(String[] args) {
// ExamPaper examPaper = new ExamPaper();
// System.out.println(examPaper);
ExamPaper examPaper = (ExamPaper)BeanUtils.copy(new ExamPaper());
System.out.println(examPaper);
// #输出内容:
// ExamPaper{examinationPaperId='null', leavTime='null', organizationId='null', id='null', examRoomId='null', userId='null', specialtyCode='null', postionCode='null', gradeCode='null', examStartTime='null', examEndTime='null', singleSelectionImpCount='null', multiSelectionImpCount='null', judgementImpCount='null', examTime='null', fullScore='null', passScore='null', userName='null', score='null', resut='null', singleOkCount='null', multiOkCount='null', judgementOkCount='null'}
}
}
- general文件夹
package com.general;
public interface IPrototype<T> {
T clone();
}
package com.general;
public class ConcretePrototype implements IPrototype {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public ConcretePrototype clone() {
ConcretePrototype concretePrototype = new ConcretePrototype();
concretePrototype.setAge(this.age);
concretePrototype.setName(this.name);
return concretePrototype;
}
@Override
public String toString() {
return "ConcretePrototype{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
package com.general;
/**
* generalClient-Test
*/
public class Client {
public static void main(String[] args) {
//创建原型对象
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAge(18);
prototype.setName("China");
System.out.println(prototype);
//拷贝原型对象
ConcretePrototype cloneType = prototype.clone();
System.out.println(cloneType);
// # 输出内容:
// ConcretePrototype{age=18, name='China'}
// ConcretePrototype{age=18, name='China'}
}
}
- shallow文件夹
package com.shallow;
import lombok.Data;
import java.util.List;
@Data
public class ConcretePrototype implements Cloneable {
private int age;
private String name;
private List<String> hobbies;
@Override
public ConcretePrototype clone() {
try {
return (ConcretePrototype)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "ConcretePrototype{" +
"age=" + age +
", name='" + name + '\'' +
", hobbies=" + hobbies +
'}';
}
}
package com.shallow;
import java.util.ArrayList;
import java.util.List;
/**
* shallowClient-Test
*/
public class Client {
public static void main(String[] args) {
//创建原型对象
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAge(18);
prototype.setName("China");
List<String> hobbies = new ArrayList<String>();
hobbies.add("书法");
hobbies.add("美术");
prototype.setHobbies(hobbies);
//拷贝原型对象
ConcretePrototype cloneType = prototype.clone();
cloneType.getHobbies().add("技术控");
System.out.println("原型对象:" + prototype);
System.out.println("克隆对象:" + cloneType);
System.out.println(prototype == cloneType);
System.out.println("原型对象的爱好:" + prototype.getHobbies());
System.out.println("克隆对象的爱好:" + cloneType.getHobbies());
System.out.println(prototype.getHobbies() == cloneType.getHobbies());
// #输出内容:
// 原型对象:ConcretePrototype{age=18, name='China', hobbies=[书法, 美术, 技术控]}
// 克隆对象:ConcretePrototype{age=18, name='China', hobbies=[书法, 美术, 技术控]}
// false
// 原型对象的爱好:[书法, 美术, 技术控]
// 克隆对象的爱好:[书法, 美术, 技术控]
// true
}
}
深克隆
代码示栗:
- deep文件夹
package com.deep;
import lombok.Data;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
@Data
public class ConcretePrototype implements Cloneable,Serializable {
private int age;
private String name;
private List<String> hobbies;
@Override
public ConcretePrototype clone() {
try {
return (ConcretePrototype)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
public ConcretePrototype deepCloneHobbies(){
try {
ConcretePrototype result = (ConcretePrototype)super.clone();
result.hobbies = (List)((ArrayList)result.hobbies).clone();
return result;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
// 演示示列-1
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);
return (ConcretePrototype)ois.readObject();
}catch (Exception e){
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "ConcretePrototype{" +
"age=" + age +
", name='" + name + '\'' +
", hobbies=" + hobbies +
'}';
}
}
package com.deep;
import java.util.ArrayList;
import java.util.List;
/**
* deepClient-Test
*/
public class Client {
public static void main(String[] args) {
//创建原型对象
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAge(18);
prototype.setName("Tom");
List<String> hobbies = new ArrayList<String>();
hobbies.add("书法");
hobbies.add("美术");
prototype.setHobbies(hobbies);
//拷贝原型对象
ConcretePrototype cloneType = prototype.deepCloneHobbies();
cloneType.getHobbies().add("技术控");
System.out.println("原型对象:" + prototype);
System.out.println("克隆对象:" + cloneType);
System.out.println(prototype == cloneType);
System.out.println("原型对象的爱好:" + prototype.getHobbies());
System.out.println("克隆对象的爱好:" + cloneType.getHobbies());
System.out.println(prototype.getHobbies() == cloneType.getHobbies());
// #输出内容:
// 原型对象:ConcretePrototype{age=18, name='Tom', hobbies=[书法, 美术]}
// 克隆对象:ConcretePrototype{age=18, name='Tom', hobbies=[书法, 美术, 技术控]}
// false
// 原型对象的爱好:[书法, 美术]
// 克隆对象的爱好:[书法, 美术, 技术控]
// false
}
}
单例模式—克隆
代码示栗:
- singleton文件夹
package com.singleton;
import java.util.ArrayList;
import java.util.List;
/**
* singletonClient-Test
*/
public class Client {
public static void main(String[] args) {
//创建原型对象
ConcretePrototype prototype = ConcretePrototype.getInstance();
prototype.setAge(18);
prototype.setName("China");
List<String> hobbies = new ArrayList<String>();
hobbies.add("书法");
hobbies.add("美术");
prototype.setHobbies(hobbies);
//拷贝原型对象
ConcretePrototype cloneType = prototype.clone();
cloneType.getHobbies().add("技术控");
System.out.println("原型对象:" + prototype);
System.out.println("克隆对象:" + cloneType);
System.out.println(prototype == cloneType);
System.out.println("原型对象的爱好:" + prototype.getHobbies());
System.out.println("克隆对象的爱好:" + cloneType.getHobbies());
System.out.println(prototype.getHobbies() == cloneType.getHobbies());
// #输出内容:
// 原型对象:ConcretePrototype{age=18, name='China', hobbies=[书法, 美术, 技术控]}
// 克隆对象:ConcretePrototype{age=18, name='China', hobbies=[书法, 美术, 技术控]}
// true
// 原型对象的爱好:[书法, 美术, 技术控]
// 克隆对象的爱好:[书法, 美术, 技术控]
// true
}
}
package com.singleton;
import lombok.Data;
import java.util.List;
@Data
public class ConcretePrototype implements Cloneable {
private int age;
private String name;
private List<String> hobbies;
private static ConcretePrototype instance = new ConcretePrototype();
private ConcretePrototype(){}
public static ConcretePrototype getInstance(){
return instance;
}
@Override
public ConcretePrototype clone() {
return instance;
}
@Override
public String toString() {
return "ConcretePrototype{" +
"age=" + age +
", name='" + name + '\'' +
", hobbies=" + hobbies +
'}';
}
}
建造者模式(BuiIder Pattern)
建造者模式(BuiIder Pattern)是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
特征:用户只需指定需要建造的类型就可以获得对象,建造过程及细节不需要了解。
属于创建型模式。
-
建造者模式的适用场景
适用于创建对象需要很多步骤,但是步骤的顺序不一定固定。
如果一个对象有非常复杂的内部结构(很多属性)
把复杂对象的创建和使用分离 -
建造者模式的优点
封装性好,创建和使用分离
扩展性好,建造类之间独立、一定程度上解耦 -
建造者模式的缺点
产生多余的Builder对象
产品内部发生变化,建造者都要修改,成本较大 -
建造者模式和工厂模式的区别
- 建造者模式更加注重方法的调用顺序,工厂模式注重于创建对象。
- 创建对象的力度不同,建造者模式创建复杂的对象,由各种复杂的部件组成,工厂模式创建出来的都一样。
- 关注点:工厂模式模式只需要把对象创建出来就可以了,而建造者模式中不仅要创建出这个对象,还要知道这个对象由哪些部件组成。
- 建造者模式根据建造过程中的顺序不一样,最终的对象部件组成也不一样。
代码示栗:
- simple文件夹
package com.simple;
import lombok.Data;
@Data
public class Course {
private String name;
private String ppt;
private String video;
private String note;
private String homework;
@Override
public String toString() {
return "CourseBuilder{" +
"name='" + name + '\'' +
", ppt='" + ppt + '\'' +
", video='" + video + '\'' +
", note='" + note + '\'' +
", homework='" + homework + '\'' +
'}';
}
}
package com.simple;
public class CourseBuilder{
private Course course = new Course();
public void addName(String name) {
course.setName(name);
}
public void addPPT(String ppt) {
course.setPpt(ppt);
}
public void addVideo(String video) {
course.setVideo(video);
}
public void addNote(String note) {
course.setNote(note);
}
public void addHomework(String homework) {
course.setHomework(homework);
}
public Course build() {
return course;
}
}
package com.simple;
/**
* simpleTest
*/
public class Test {
public static void main(String[] args) {
CourseBuilder builder = new CourseBuilder();
builder.addName("设计模式");
builder.addPPT("【PPT课件】");
builder.addVideo("【回放视频】");
builder.addNote("【课堂笔记】");
builder.addHomework("【课后作业】");
System.out.println(builder.build());
// #输出内容:
// CourseBuilder{name='设计模式', ppt='【PPT课件】', video='【回放视频】', note='【课堂笔记】', homework='【课后作业】'}
}
}
- chain文件夹
package com.chain;
import lombok.Data;
public class CourseBuilder {
private Course course = new Course();
public CourseBuilder addName(String name) {
course.setName(name);
return this;
}
public CourseBuilder addPPT(String ppt) {
course.setPpt(ppt);
return this;
}
public CourseBuilder addVideo(String video) {
course.setVideo(video);
return this;
}
public CourseBuilder addNote(String note) {
course.setNote(note);
return this;
}
public CourseBuilder addHomework(String homework) {
course.setHomework(homework);
return this;
}
public Course build() {
return this.course;
}
@Data
public class Course {
private String name;
private String ppt;
private String video;
private String note;
private String homework;
@Override
public String toString() {
return "CourseBuilder{" +
"name='" + name + '\'' +
", ppt='" + ppt + '\'' +
", video='" + video + '\'' +
", note='" + note + '\'' +
", homework='" + homework + '\'' +
'}';
}
}
}
package com.chain;
import org.apache.ibatis.mapping.CacheBuilder;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
/**
* chainTest
*/
public class Test {
public static void main(String[] args) {
CourseBuilder builder = new CourseBuilder()
.addName("设计模式")
.addPPT("【PPT课件】")
.addVideo("【回放视频】")
.addNote("【课堂笔记】")
.addHomework("【课后作业】");
System.out.println(builder.build());
// #输出内容:
// CourseBuilder{name='设计模式', ppt='【PPT课件】', video='【回放视频】', note='【课堂笔记】', homework='【课后作业】'}
StringBuilder sb = new StringBuilder();
sb.append("");
CacheBuilder cacheBuilder = new CacheBuilder("");
cacheBuilder.blocking(false);
// cacheBuilder.
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// sqlSessionFactoryBuilder.
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();
// beanDefinitionBuilder.
}
}
建造者案例—SQL
package com.sql;
/**
* sql排序组件
*/
public class Order {
private boolean ascending; //升序还是降序
private String propertyName; //哪个字段升序,哪个字段降序
public String toString() {
return propertyName + ' ' + (ascending ? "asc" : "desc");
}
/**
* Constructor for Order.
*/
protected Order(String propertyName, boolean ascending) {
this.propertyName = propertyName;
this.ascending = ascending;
}
/**
* Ascending order
*
* @param propertyName
* @return Order
*/
public static Order asc(String propertyName) {
return new Order(propertyName, true);
}
/**
* Descending order
*
* @param propertyName
* @return Order
*/
public static Order desc(String propertyName) {
return new Order(propertyName, false);
}
}
package com.sql;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* QueryRule,主要功能用于构造查询条件
*
*/
public final class QueryRule implements Serializable
{
private static final long serialVersionUID = 1L;
public static final int ASC_ORDER = 101;
public static final int DESC_ORDER = 102;
public static final int LIKE = 1;
public static final int IN = 2;
public static final int NOTIN = 3;
public static final int BETWEEN = 4;
public static final int EQ = 5;
public static final int NOTEQ = 6;
public static final int GT = 7;
public static final int GE = 8;
public static final int LT = 9;
public static final int LE = 10;
public static final int ISNULL = 11;
public static final int ISNOTNULL = 12;
public static final int ISEMPTY = 13;
public static final int ISNOTEMPTY = 14;
public static final int AND = 201;
public static final int OR = 202;
private List<Rule> ruleList = new ArrayList<Rule>();
private List<QueryRule> queryRuleList = new ArrayList<QueryRule>();
private String propertyName;
private QueryRule() {}
private QueryRule(String propertyName) {
this.propertyName = propertyName;
}
public static QueryRule getInstance() {
return new QueryRule();
}
/**
* 添加升序规则
* @param propertyName
* @return
*/
public QueryRule addAscOrder(String propertyName) {
this.ruleList.add(new Rule(ASC_ORDER, propertyName));
return this;
}
/**
* 添加降序规则
* @param propertyName
* @return
*/
public QueryRule addDescOrder(String propertyName) {
this.ruleList.add(new Rule(DESC_ORDER, propertyName));
return this;
}
public QueryRule andIsNull(String propertyName) {
this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(AND));
return this;
}
public QueryRule andIsNotNull(String propertyName) {
this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(AND));
return this;
}
public QueryRule andIsEmpty(String propertyName) {
this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(AND));
return this;
}
public QueryRule andIsNotEmpty(String propertyName) {
this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(AND));
return this;
}
public QueryRule andLike(String propertyName, Object value) {
this.ruleList.add(new Rule(LIKE, propertyName, new Object[] { value }).setAndOr(AND));
return this;
}
public QueryRule andEqual(String propertyName, Object value) {
this.ruleList.add(new Rule(EQ, propertyName, new Object[] { value }).setAndOr(AND));
return this;
}
public QueryRule andBetween(String propertyName, Object... values) {
this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(AND));
return this;
}
public QueryRule andIn(String propertyName, List<Object> values) {
this.ruleList.add(new Rule(IN, propertyName, new Object[] { values }).setAndOr(AND));
return this;
}
public QueryRule andIn(String propertyName, Object... values) {
this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(AND));
return this;
}
public QueryRule andNotIn(String propertyName, List<Object> values) {
this.ruleList.add(new Rule(NOTIN, propertyName, new Object[] { values }).setAndOr(AND));
return this;
}
public QueryRule orNotIn(String propertyName, Object... values) {
this.ruleList.add(new Rule(NOTIN, propertyName, values).setAndOr(OR));
return this;
}
public QueryRule andNotEqual(String propertyName, Object value) {
this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[] { value }).setAndOr(AND));
return this;
}
public QueryRule andGreaterThan(String propertyName, Object value) {
this.ruleList.add(new Rule(GT, propertyName, new Object[] { value }).setAndOr(AND));
return this;
}
public QueryRule andGreaterEqual(String propertyName, Object value) {
this.ruleList.add(new Rule(GE, propertyName, new Object[] { value }).setAndOr(AND));
return this;
}
public QueryRule andLessThan(String propertyName, Object value) {
this.ruleList.add(new Rule(LT, propertyName, new Object[] { value }).setAndOr(AND));
return this;
}
public QueryRule andLessEqual(String propertyName, Object value) {
this.ruleList.add(new Rule(LE, propertyName, new Object[] { value }).setAndOr(AND));
return this;
}
public QueryRule orIsNull(String propertyName) {
this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(OR));
return this;
}
public QueryRule orIsNotNull(String propertyName) {
this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(OR));
return this;
}
public QueryRule orIsEmpty(String propertyName) {
this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(OR));
return this;
}
public QueryRule orIsNotEmpty(String propertyName) {
this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(OR));
return this;
}
public QueryRule orLike(String propertyName, Object value) {
this.ruleList.add(new Rule(LIKE, propertyName, new Object[] { value }).setAndOr(OR));
return this;
}
public QueryRule orEqual(String propertyName, Object value) {
this.ruleList.add(new Rule(EQ, propertyName, new Object[] { value }).setAndOr(OR));
return this;
}
public QueryRule orBetween(String propertyName, Object... values) {
this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(OR));
return this;
}
public QueryRule orIn(String propertyName, List<Object> values) {
this.ruleList.add(new Rule(IN, propertyName, new Object[] { values }).setAndOr(OR));
return this;
}
public QueryRule orIn(String propertyName, Object... values) {
this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(OR));
return this;
}
public QueryRule orNotEqual(String propertyName, Object value) {
this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[] { value }).setAndOr(OR));
return this;
}
public QueryRule orGreaterThan(String propertyName, Object value) {
this.ruleList.add(new Rule(GT, propertyName, new Object[] { value }).setAndOr(OR));
return this;
}
public QueryRule orGreaterEqual(String propertyName, Object value) {
this.ruleList.add(new Rule(GE, propertyName, new Object[] { value }).setAndOr(OR));
return this;
}
public QueryRule orLessThan(String propertyName, Object value) {
this.ruleList.add(new Rule(LT, propertyName, new Object[] { value }).setAndOr(OR));
return this;
}
public QueryRule orLessEqual(String propertyName, Object value) {
this.ruleList.add(new Rule(LE, propertyName, new Object[] { value }).setAndOr(OR));
return this;
}
public List<Rule> getRuleList() {
return this.ruleList;
}
public List<QueryRule> getQueryRuleList() {
return this.queryRuleList;
}
public String getPropertyName() {
return this.propertyName;
}
protected class Rule implements Serializable {
private static final long serialVersionUID = 1L;
private int type; //规则的类型
private String property_name;
private Object[] values;
private int andOr = AND;
public Rule(int paramInt, String paramString) {
this.property_name = paramString;
this.type = paramInt;
}
public Rule(int paramInt, String paramString,
Object[] paramArrayOfObject) {
this.property_name = paramString;
this.values = paramArrayOfObject;
this.type = paramInt;
}
public Rule setAndOr(int andOr){
this.andOr = andOr;
return this;
}
public int getAndOr(){
return this.andOr;
}
public Object[] getValues() {
return this.values;
}
public int getType() {
return this.type;
}
public String getPropertyName() {
return this.property_name;
}
}
}
package com.sql;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.ArrayUtils;
import com.gupaoedu.vip.pattern.builder.sql.QueryRule.Rule;
import org.apache.commons.lang.StringUtils;
/**
* 根据QueryRule自动构建sql语句
*
*/
public class QueryRuleSqlBuilder {
private int CURR_INDEX = 0; //记录参数所在的位置
private List<String> properties; //保存列名列表
private List<Object> values; //保存参数值列表
private List<Order> orders; //保存排序规则列表
private String whereSql = "";
private String orderSql = "";
private Object [] valueArr = new Object[]{};
private Map<Object,Object> valueMap = new HashMap<Object,Object>();
/**
* 或得查询条件
* @return
*/
private String getWhereSql(){
return this.whereSql;
}
/**
* 获得排序条件
* @return
*/
private String getOrderSql(){
return this.orderSql;
}
/**
* 获得参数值列表
* @return
*/
public Object [] getValues(){
return this.valueArr;
}
/**
* 获取参数列表
* @return
*/
private Map<Object,Object> getValueMap(){
return this.valueMap;
}
/**
* 创建SQL构造器
* @param queryRule
*/
public QueryRuleSqlBuilder(QueryRule queryRule) {
CURR_INDEX = 0;
properties = new ArrayList<String>();
values = new ArrayList<Object>();
orders = new ArrayList<Order>();
for (QueryRule.Rule rule : queryRule.getRuleList()) {
switch (rule.getType()) {
case QueryRule.BETWEEN:
processBetween(rule);
break;
case QueryRule.EQ:
processEqual(rule);
break;
case QueryRule.LIKE:
processLike(rule);
break;
case QueryRule.NOTEQ:
processNotEqual(rule);
break;
case QueryRule.GT:
processGreaterThen(rule);
break;
case QueryRule.GE:
processGreaterEqual(rule);
break;
case QueryRule.LT:
processLessThen(rule);
break;
case QueryRule.LE:
processLessEqual(rule);
break;
case QueryRule.IN:
processIN(rule);
break;
case QueryRule.NOTIN:
processNotIN(rule);
break;
case QueryRule.ISNULL:
processIsNull(rule);
break;
case QueryRule.ISNOTNULL:
processIsNotNull(rule);
break;
case QueryRule.ISEMPTY:
processIsEmpty(rule);
break;
case QueryRule.ISNOTEMPTY:
processIsNotEmpty(rule);
break;
case QueryRule.ASC_ORDER:
processOrder(rule);
break;
case QueryRule.DESC_ORDER:
processOrder(rule);
break;
default:
throw new IllegalArgumentException("type " + rule.getType() + " not supported.");
}
}
//拼装where语句
appendWhereSql();
//拼装排序语句
appendOrderSql();
//拼装参数值
appendValues();
}
/**
* 去掉order
*
* @param sql
* @return
*/
private String removeOrders(String sql) {
Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(sql);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, "");
}
m.appendTail(sb);
return sb.toString();
}
/**
* 去掉select
*
* @param sql
* @return
*/
private String removeSelect(String sql) {
if(sql.toLowerCase().matches("from\\s+")){
int beginPos = sql.toLowerCase().indexOf("from");
return sql.substring(beginPos);
}else{
return sql;
}
}
/**
* 处理like
* @param rule
*/
private void processLike(QueryRule.Rule rule) {
if (ArrayUtils.isEmpty(rule.getValues())) {
return;
}
Object obj = rule.getValues()[0];
if (obj != null) {
String value = obj.toString();
if (!StringUtils.isEmpty(value)) {
value = value.replace('*', '%');
obj = value;
}
}
add(rule.getAndOr(),rule.getPropertyName(),"like","%"+rule.getValues()[0]+"%");
}
/**
* 处理between
* @param rule
*/
private void processBetween(QueryRule.Rule rule) {
if ((ArrayUtils.isEmpty(rule.getValues()))
|| (rule.getValues().length < 2)) {
return;
}
add(rule.getAndOr(),rule.getPropertyName(),"","between",rule.getValues()[0],"and");
add(0,"","","",rule.getValues()[1],"");
}
/**
* 处理 =
* @param rule
*/
private void processEqual(QueryRule.Rule rule) {
if (ArrayUtils.isEmpty(rule.getValues())) {
return;
}
add(rule.getAndOr(),rule.getPropertyName(),"=",rule.getValues()[0]);
}
/**
* 处理 <>
* @param rule
*/
private void processNotEqual(QueryRule.Rule rule) {
if (ArrayUtils.isEmpty(rule.getValues())) {
return;
}
add(rule.getAndOr(),rule.getPropertyName(),"<>",rule.getValues()[0]);
}
/**
* 处理 >
* @param rule
*/
private void processGreaterThen(
QueryRule.Rule rule) {
if (ArrayUtils.isEmpty(rule.getValues())) {
return;
}
add(rule.getAndOr(),rule.getPropertyName(),">",rule.getValues()[0]);
}
/**
* 处理>=
* @param rule
*/
private void processGreaterEqual(
QueryRule.Rule rule) {
if (ArrayUtils.isEmpty(rule.getValues())) {
return;
}
add(rule.getAndOr(),rule.getPropertyName(),">=",rule.getValues()[0]);
}
/**
* 处理<
* @param rule
*/
private void processLessThen(QueryRule.Rule rule) {
if (ArrayUtils.isEmpty(rule.getValues())) {
return;
}
add(rule.getAndOr(),rule.getPropertyName(),"<",rule.getValues()[0]);
}
/**
* 处理<=
* @param rule
*/
private void processLessEqual(
QueryRule.Rule rule) {
if (ArrayUtils.isEmpty(rule.getValues())) {
return;
}
add(rule.getAndOr(),rule.getPropertyName(),"<=",rule.getValues()[0]);
}
/**
* 处理 is null
* @param rule
*/
private void processIsNull(QueryRule.Rule rule) {
add(rule.getAndOr(),rule.getPropertyName(),"is null",null);
}
/**
* 处理 is not null
* @param rule
*/
private void processIsNotNull(QueryRule.Rule rule) {
add(rule.getAndOr(),rule.getPropertyName(),"is not null",null);
}
/**
* 处理 <>''
* @param rule
*/
private void processIsNotEmpty(QueryRule.Rule rule) {
add(rule.getAndOr(),rule.getPropertyName(),"<>","''");
}
/**
* 处理 =''
* @param rule
*/
private void processIsEmpty(QueryRule.Rule rule) {
add(rule.getAndOr(),rule.getPropertyName(),"=","''");
}
/**
* 处理in和not in
* @param rule
* @param name
*/
private void inAndNotIn(QueryRule.Rule rule,String name){
if (ArrayUtils.isEmpty(rule.getValues())) {
return;
}
if ((rule.getValues().length == 1) && (rule.getValues()[0] != null)
&& (rule.getValues()[0] instanceof List)) {
List<Object> list = (List) rule.getValues()[0];
if ((list != null) && (list.size() > 0)){
for (int i = 0; i < list.size(); i++) {
if(i == 0 && i == list.size() - 1){
add(rule.getAndOr(),rule.getPropertyName(),"",name + " (",list.get(i),")");
}else if(i == 0 && i < list.size() - 1){
add(rule.getAndOr(),rule.getPropertyName(),"",name + " (",list.get(i),"");
}
if(i > 0 && i < list.size() - 1){
add(0,"",",","",list.get(i),"");
}
if(i == list.size() - 1 && i != 0){
add(0,"",",","",list.get(i),")");
}
}
}
} else {
Object[] list = rule.getValues();
for (int i = 0; i < list.length; i++) {
if(i == 0 && i == list.length - 1){
add(rule.getAndOr(),rule.getPropertyName(),"",name + " (",list[i],")");
}else if(i == 0 && i < list.length - 1){
add(rule.getAndOr(),rule.getPropertyName(),"",name + " (",list[i],"");
}
if(i > 0 && i < list.length - 1){
add(0,"",",","",list[i],"");
}
if(i == list.length - 1 && i != 0){
add(0,"",",","",list[i],")");
}
}
}
}
/**
* 处理 not in
* @param rule
*/
private void processNotIN(QueryRule.Rule rule){
inAndNotIn(rule,"not in");
}
/**
* 处理 in
* @param rule
*/
private void processIN(QueryRule.Rule rule) {
inAndNotIn(rule,"in");
}
/**
* 处理 order by
* @param rule 查询规则
*/
private void processOrder(Rule rule) {
switch (rule.getType()) {
case QueryRule.ASC_ORDER:
// propertyName非空
if (!StringUtils.isEmpty(rule.getPropertyName())) {
orders.add(Order.asc(rule.getPropertyName()));
}
break;
case QueryRule.DESC_ORDER:
// propertyName非空
if (!StringUtils.isEmpty(rule.getPropertyName())) {
orders.add(Order.desc(rule.getPropertyName()));
}
break;
default:
break;
}
}
/**
* 加入到sql查询规则队列
* @param andOr and 或者 or
* @param key 列名
* @param split 列名与值之间的间隔
* @param value 值
*/
private void add(int andOr,String key,String split ,Object value){
add(andOr,key,split,"",value,"");
}
/**
* 加入到sql查询规则队列
* @param andOr and 或则 or
* @param key 列名
* @param split 列名与值之间的间隔
* @param prefix 值前缀
* @param value 值
* @param suffix 值后缀
*/
private void add(int andOr,String key,String split ,String prefix,Object value,String suffix){
String andOrStr = (0 == andOr ? "" :(QueryRule.AND == andOr ? " and " : " or "));
properties.add(CURR_INDEX, andOrStr + key + " " + split + prefix + (null != value ? " ? " : " ") + suffix);
if(null != value){
values.add(CURR_INDEX,value);
CURR_INDEX ++;
}
}
/**
* 拼装 where 语句
*/
private void appendWhereSql(){
StringBuffer whereSql = new StringBuffer();
for (String p : properties) {
whereSql.append(p);
}
this.whereSql = removeSelect(removeOrders(whereSql.toString()));
}
/**
* 拼装排序语句
*/
private void appendOrderSql(){
StringBuffer orderSql = new StringBuffer();
for (int i = 0 ; i < orders.size(); i ++) {
if(i > 0 && i < orders.size()){
orderSql.append(",");
}
orderSql.append(orders.get(i).toString());
}
this.orderSql = removeSelect(removeOrders(orderSql.toString()));
}
/**
* 拼装参数值
*/
private void appendValues(){
Object [] val = new Object[values.size()];
for (int i = 0; i < values.size(); i ++) {
val[i] = values.get(i);
valueMap.put(i, values.get(i));
}
this.valueArr = val;
}
public String builder(String tableName){
String ws = removeFirstAnd(this.getWhereSql());
String whereSql = ("".equals(ws) ? ws : (" where " + ws));
String sql = "select * from " + tableName + whereSql;
Object [] values = this.getValues();
String orderSql = this.getOrderSql();
orderSql = (StringUtils.isEmpty(orderSql) ? " " : (" order by " + orderSql));
sql += orderSql;
return sql;
}
private String removeFirstAnd(String sql){
if(StringUtils.isEmpty(sql)){return sql;}
return sql.trim().toLowerCase().replaceAll("^\\s*and", "") + " ";
}
}
package com.sql;
import java.util.Arrays;
/**
* sqlTest
*/
public class Test {
public static void main(String[] args) {
QueryRule queryRule = QueryRule.getInstance();
queryRule.addAscOrder("age");
queryRule.andEqual("addr","Changsha");
queryRule.andLike("name","China");
QueryRuleSqlBuilder builder = new QueryRuleSqlBuilder(queryRule);
System.out.println(builder.builder("t_member"));
System.out.println("Params: " + Arrays.toString(builder.getValues()));
// #输出内容:
// select * from t_member where addr = ? and name like ? order by age asc
// Params: [Changsha, %China%]
}
}
结构型模式
代理模式(Proxy Pattern)
代理模式(Proxy Pattern)是指为其他对象提供一种代理,以控制对这个对象的访问。
代理对象在客服端和目标对象之间起到中介作用。
属于结构型设计模式。
-
代理模式的适用场景
保护目标对象
增强目标对象 -
##静态代理
显式声明被代理对象 -
##动态代理
动态配置和替换被代理对象 -
代理模式的优点
代理模式能将代理对象与真实被调用的目标对象分离。
一定程度上降低了系统的耦合程度,易于扩展。
代理可以起到保护目标对象的作用。
增强目标对象的职责。 -
Spring中的代理选择原则
1、当Bean有实现接口时,Spring就会用JDK的动态代理。
2、当Bean没有实现接口时,Spring选择CGLib。
3、Spring可以通过配置强制使用CGLib,只需在Spring的配置文件中加入如下代码:
<aop : aspectj-autoproxy proxy-target-class="true" />
静态代理
显式声明被代理对象
代码示栗:
- staticproxy文件夹
package com.staticproxy;
/**
* staticproxy-Test
*/
public class Test {
public static void main(String[] args) {
ZhangLaosan zhangLaosan = new ZhangLaosan(new ZhangSan());
zhangLaosan.findLove();
// #输出内容:
// 张老三开始物色
// 儿子要求:肤白貌美大长腿
// 开始交往
}
}
package com.staticproxy;
public interface IPerson {
void findLove();
}
package com.staticproxy;
public class ZhangLaosan implements IPerson {
private ZhangSan zhangsan;
public ZhangLaosan(ZhangSan zhangsan) {
this.zhangsan = zhangsan;
}
public void findLove() {
System.out.println("张老三开始物色");
zhangsan.findLove();
System.out.println("开始交往");
}
}
package com.staticproxy;
public class ZhangSan implements IPerson {
public void findLove() {
System.out.println("儿子要求:肤白貌美大长腿");
}
}
- general文件夹
package com.general;
/**
* generalClient-Test
*/
public class Client {
public static void main(String[] args) {
Proxy proxy = new Proxy(new RealSubject());
proxy.request();
// #输出内容:
// called before request().
// real service is called.
// called after request().
}
}
package com.general;
public interface ISubject {
void request();
}
package com.general;
public class Proxy implements ISubject {
private ISubject subject;
public Proxy(ISubject subject){
this.subject = subject;
}
public void request() {
before();
subject.request();
after();
}
public void before(){
System.out.println("called before request().");
}
public void after(){
System.out.println("called after request().");
}
}
package com.general;
public class RealSubject implements ISubject {
public void request() {
System.out.println("real service is called.");
}
}
- jdkproxy文件夹
package com.jdkproxy;
/**
* jdkproxyTest
*/
public class Test {
public static void main(String[] args) {
JdkMeipo jdkMeipo = new JdkMeipo();
IPerson zhangsan = jdkMeipo.getInstance(new Zhangsan());
zhangsan.findLove();
IPerson zhaoliu = jdkMeipo.getInstance(new ZhaoLiu());
zhaoliu.findLove();
// #输出内容:
// 我是媒婆,已经收集到你的需求,开始物色
// 张三要求:肤白貌美大长腿
// 双方同意,开始交往
// 我是媒婆,已经收集到你的需求,开始物色
// 赵六要求:有车有房学历高
// 双方同意,开始交往
}
}
package com.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkMeipo implements InvocationHandler {
private IPerson target;
public IPerson getInstance(IPerson target){
this.target = target;
Class<?> clazz = target.getClass();
return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(this.target,args);
after();
return result;
}
private void after() {
System.out.println("双方同意,开始交往");
}
private void before() {
System.out.println("我是媒婆,已经收集到你的需求,开始物色");
}
}
package com.jdkproxy;
public interface IPerson {
void findLove();
void buyInsure();
}
package com.jdkproxy;
public class ZhaoLiu implements IPerson {
public void findLove() {
System.out.println("赵六要求:有车有房学历高");
}
public void buyInsure() {
}
}
package com.jdkproxy;
public class Zhangsan implements IPerson {
public void findLove() {
System.out.println("张三要求:肤白貌美大长腿");
}
public void buyInsure() {
System.out.println("30万");
}
}
- cglibproxy文件夹
<!-- Maven -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>
package com.cglibproxy;
import net.sf.cglib.core.DebuggingClassWriter;
/**
* CglibTest
*/
public class CglibTest {
public static void main(String[] args) {
Customer obj = (Customer) new CGlibMeipo().getInstance(Customer.class);
System.out.println(obj);
obj.findLove();
// #输出内容:
// com.gupaoedu.vip.pattern.proxy.dynamicproxy.cglibproxy.Customer$$EnhancerByCGLIB$$123efa7c@14514713
// 我是媒婆,我要给你找对象,现在已经确认你的需求
// 开始物色
// 儿子要求:肤白貌美大长腿
// OK的话,准备办事
}
}
package com.cglibproxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGlibMeipo implements MethodInterceptor {
public Object getInstance(Class<?> clazz) throws Exception{
//相当于Proxy,代理的工具类
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = methodProxy.invokeSuper(o,objects);
after();
return obj;
}
private void before(){
System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
System.out.println("开始物色");
}
private void after(){
System.out.println("OK的话,准备办事");
}
}
package com.cglibproxy;
public class Customer {
public void findLove(){
System.out.println("儿子要求:肤白貌美大长腿");
}
}
动态代理
动态配置和替换被代理对象
代码示栗:
- cglibproxy文件夹
<!-- Maven -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>
package com.cglibproxy;
import net.sf.cglib.core.DebuggingClassWriter;
/**
* CglibTest
*/
public class CglibTest {
public static void main(String[] args) {
try {
//JDK是采用读取接口的信息
//CGLib覆盖父类方法
//目的:都是生成一个新的类,去实现增强代码逻辑的功能
//JDK Proxy 对于用户而言,必须要有一个接口实现,目标类相对来说复杂
//CGLib 可以代理任意一个普通的类,没有任何要求
//CGLib 生成代理逻辑更复杂,效率,调用效率更高,生成一个包含了所有的逻辑的FastClass,不再需要反射调用
//JDK Proxy生成代理的逻辑简单,执行效率相对要低,每次都要反射动态调用
//CGLib 有个坑,CGLib不能代理final的方法
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E://cglib_proxy_classes");
Customer obj = (Customer) new CGlibMeipo().getInstance(Customer.class);
System.out.println(obj);
obj.findLove();
// #输出内容:
// com.gupaoedu.vip.pattern.proxy.dynamicproxy.cglibproxy.Customer$$EnhancerByCGLIB$$123efa7c@14514713
// 我是媒婆,我要给你找对象,现在已经确认你的需求
// 开始物色
// 儿子要求:肤白貌美大长腿
// OK的话,准备办事
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.cglibproxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGlibMeipo implements MethodInterceptor {
public Object getInstance(Class<?> clazz) throws Exception{
//相当于Proxy,代理的工具类
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = methodProxy.invokeSuper(o,objects);
after();
return obj;
}
private void before(){
System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
System.out.println("开始物色");
}
private void after(){
System.out.println("OK的话,准备办事");
}
}
package com.cglibproxy;
public class Customer {
public void findLove(){
System.out.println("儿子要求:肤白貌美大长腿");
}
}
- proxy文件夹
- //1、动态生成源码.java文件
- //2、 Java文件输出到磁盘,保存为文f$Proxye.java
- //3、把.java文件编译成成SProxyo.class文件
- //4、把生成的.cLass文件加载到门v 中 //5、返回新的代理对象
package com.proxy;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* 用来生成源代码的工具类
*/
public class GPProxy {
public static final String ln = "\r\n";
public static Object newProxyInstance(GPClassLoader classLoader, Class<?> [] interfaces, GPInvocationHandler h){
try {
//1、动态生成源代码.java文件
String src = generateSrc(interfaces);
// System.out.println(src);
//2、Java文件输出磁盘
String filePath = GPProxy.class.getResource("").getPath();
// System.out.println(filePath);
File f = new File(filePath + "$Proxy0.java");
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//3、把生成的.java文件编译成.class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);
Iterable iterable = manage.getJavaFileObjects(f);
JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);
task.call();
manage.close();
//4、编译生成的.class文件加载到JVM中来
Class proxyClass = classLoader.findClass("$Proxy0");
Constructor c = proxyClass.getConstructor(GPInvocationHandler.class);
f.delete();
//5、返回字节码重组以后的新的代理对象
return c.newInstance(h);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
private static String generateSrc(Class<?>[] interfaces){
StringBuffer sb = new StringBuffer();
sb.append(GPProxy.class.getPackage() + ";" + ln);
sb.append("import " + interfaces[0].getName() + ";" + ln);
sb.append("import java.lang.reflect.*;" + ln);
sb.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
sb.append("GPInvocationHandler h;" + ln);
sb.append("public $Proxy0(GPInvocationHandler h) { " + ln);
sb.append("this.h = h;");
sb.append("}" + ln);
for (Method m : interfaces[0].getMethods()){
Class<?>[] params = m.getParameterTypes();
StringBuffer paramNames = new StringBuffer();
StringBuffer paramValues = new StringBuffer();
StringBuffer paramClasses = new StringBuffer();
for (int i = 0; i < params.length; i++) {
Class clazz = params[i];
String type = clazz.getName();
String paramName = toLowerFirstCase(clazz.getSimpleName());
paramNames.append(type + " " + paramName);
paramValues.append(paramName);
paramClasses.append(clazz.getName() + ".class");
if(i > 0 && i < params.length-1){
paramNames.append(",");
paramClasses.append(",");
paramValues.append(",");
}
}
sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "(" + paramNames.toString() + ") {" + ln);
sb.append("try{" + ln);
sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{" + paramClasses.toString() + "});" + ln);
sb.append((hasReturnValue(m.getReturnType()) ? "return " : "") + getCaseCode("this.h.invoke(this,m,new Object[]{" + paramValues + "})",m.getReturnType()) + ";" + ln);
sb.append("}catch(Error _ex) { }");
sb.append("catch(Throwable e){" + ln);
sb.append("throw new UndeclaredThrowableException(e);" + ln);
sb.append("}");
sb.append(getReturnEmptyCode(m.getReturnType()));
sb.append("}");
}
sb.append("}" + ln);
return sb.toString();
}
private static Map<Class,Class> mappings = new HashMap<Class, Class>();
static {
mappings.put(int.class,Integer.class);
}
private static String getReturnEmptyCode(Class<?> returnClass){
if(mappings.containsKey(returnClass)){
return "return 0;";
}else if(returnClass == void.class){
return "";
}else {
return "return null;";
}
}
private static String getCaseCode(String code,Class<?> returnClass){
if(mappings.containsKey(returnClass)){
return "((" + mappings.get(returnClass).getName() + ")" + code + ")." + returnClass.getSimpleName() + "Value()";
}
return code;
}
private static boolean hasReturnValue(Class<?> clazz){
return clazz != void.class;
}
private static String toLowerFirstCase(String src){
char [] chars = src.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
}
package com.proxy;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
public class GPClassLoader extends ClassLoader {
private File classPathFile;
public GPClassLoader(){
String classPath = GPClassLoader.class.getResource("").getPath();
this.classPathFile = new File(classPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = GPClassLoader.class.getPackage().getName() + "." + name;
if(classPathFile != null){
File classFile = new File(classPathFile,name.replaceAll("\\.","/") + ".class");
if(classFile.exists()){
FileInputStream in = null;
ByteArrayOutputStream out = null;
try{
in = new FileInputStream(classFile);
out = new ByteArrayOutputStream();
byte [] buff = new byte[1024];
int len;
while ((len = in.read(buff)) != -1){
out.write(buff,0,len);
}
return defineClass(className,out.toByteArray(),0,out.size());
}catch (Exception e){
e.printStackTrace();
}
}
}
return null;
}
}
package com.proxy;
import java.lang.reflect.Method;
public interface GPInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
总结:
- //JDK是采用读取接口的信息
- //CGLib覆盖父类方法
- //目的:都是生成一个新的类,去实现增强代码逻辑的功能
- //JDK Proxy 对于用户而言,必须要有一个接口实现,目标类相对来说复杂
- //CGLib 可以代理任意一个普通的类,没有任何要求
- //CGLib 生成代理逻辑更复杂,效率,调用效率更高,生成一个包含了所有的逻辑的FastClass,不再需要反射调用
- //JDK Proxy生成代理的逻辑简单,执行效率相对要低,每次都要反射动态调用
- //CGLib 有个坑,CGLib不能代理final的方法
适配器模式(Adapter Pattern)
适配器模式(Adapter Pattern)又叫做变压器模式,它的功能是将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而导致无法在一起工作的两个类能够一起工作。
属于结构型设计模式。
-
适配器模式的适用场景
1、已经存在的类,它的方法和需求不匹配(方法结果相同或相似)的情况。
2、适配器模式不是软件设计阶段考虑的设计模式,是随着软件维护,问经由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方笔t案。 -
适配器模式的优点
1、能提高类的透明性和复用,现有的类复用但不需要改变。
2、目标类和适配器类解耦,提高程序的扩展性。
3、在很多业务场景中符合开闭原则。 -
适配器模式的缺点
1、适配器编写过程需要全面考虑,可能会增加系统的复杂性。
2、增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱。
代码示栗:
- classadapter文件夹
package com.classadapter;
/**
* classadapterTest
*/
public class Test {
public static void main(String[] args) {
DC5 adapter = new PowerAdapter();
adapter.output5V();
// #输出内容:
// 输出电压220V
// 使用Adapter输入AC220V,输出DC5V
}
}
package com.classadapter;
public class PowerAdapter extends AC220 implements DC5 {
public int output5V() {
int adapterInput = super.outputAC220V();
int adapterOutput = adapterInput / 44;
System.out.println("使用Adapter输入AC" + adapterInput + "V,输出DC" + adapterOutput + "V");
return adapterOutput;
}
}
package com.classadapter;
public class AC220 {
public int outputAC220V(){
int output = 220;
System.out.println("输出电压" + output + "V");
return output;
}
}
package com.classadapter;
public interface DC5 {
int output5V();
}
- objectadapter文件夹
package com.objectadapter;
/**
* objectadapterTest
*/
public class Test {
public static void main(String[] args) {
DC5 adapter = new PowerAdapter(new AC220()) {
@Override
public int output5V() {
return super.output5V();
}
};
adapter.output5V();
// #输出内容:
// 输出电压220V
// 使用Adapter输入AC220V,输出DC5V
}
}
package com.objectadapter;
public abstract class PowerAdapter implements DC5 {
private AC220 ac220;
public PowerAdapter(AC220 ac220) {
this.ac220 = ac220;
}
public int output5V() {
int adapterInput = ac220.outputAC220V();
int adapterOutput = adapterInput / 44;
System.out.println("使用Adapter输入AC" + adapterInput + "V,输出DC" + adapterOutput + "V");
return adapterOutput;
}
}
package com.objectadapter;
public class AC220 {
public int outputAC220V(){
int output = 220;
System.out.println("输出电压" + 220 + "V");
return output;
}
}
package com.objectadapter;
public interface DC5 {
int output5V();
}
- interfaceadapter文件夹
package com.interfaceadapter;
/**
* interfaceadapterTest
*/
public class Test {
public static void main(String[] args) {
DC adapter = new PowerAdapter(new AC220());
adapter.output5V();
// #输出内容:
// 输出电压220V
// 使用Adapter输入AC220V,输出DC5V
}
}
package com.interfaceadapter;
public class PowerAdapter implements DC {
private AC220 ac220;
public PowerAdapter(AC220 ac220) {
this.ac220 = ac220;
}
public int output5V() {
int adapterInput = ac220.outputAC220V();
int adapterOutput = adapterInput / 44;
System.out.println("使用Adapter输入AC" + adapterInput + "V,输出DC" + adapterOutput + "V");
return adapterOutput;
}
public int output12V() {
return 0;
}
public int output24V() {
return 0;
}
public int output36V() {
return 0;
}
}
package com.interfaceadapter;
public class AC220 {
public int outputAC220V(){
int output = 220;
System.out.println("输出电压" + 220 + "V");
return output;
}
}
package com.interfaceadapter;
public interface DC {
int output5V();
int output12V();
int output24V();
int output36V();
}
- adapterv1文件夹
package com.adapterv1;
public class Test {
public static void main(String[] args) {
PassportForThirdAdapter adapter = new PassportForThirdAdapter();
adapter.login("tom","123456");
adapter.loginForQQ("sjooguwoersdfjhasjfsa");
adapter.loginForWechat("slfsjoljsdo8234ssdfs");
}
}
package com.adapterv1;
import com.PassportService;
import com.ResultMsg;
public class PassportForThirdAdapter extends PassportService implements IPassportForThird {
public ResultMsg loginForQQ(String openId) {
return loginForRegist(openId,null);
}
public ResultMsg loginForWechat(String openId) {
return loginForRegist(openId,null);
}
public ResultMsg loginForToken(String token) {
return loginForRegist(token,null);
}
public ResultMsg loginForTelphone(String phone, String code) {
return loginForRegist(phone,null);
}
private ResultMsg loginForRegist(String username,String password){
if(null == password){
password = "THIRD_EMPTY";
}
super.regist(username,password);
return super.login(username,password);
}
}
package com;
public class PassportService {
/**
* 注册方法
* @param username
* @param password
* @return
*/
public ResultMsg regist(String username,String password){
return new ResultMsg(200,"注册成功",new Member());
}
/**
* 登录的方法
* @param username
* @param password
* @return
*/
public ResultMsg login(String username,String password){
return null;
}
}
package com.adapterv1;
import com.ResultMsg;
public interface IPassportForThird {
ResultMsg loginForQQ(String openId);
ResultMsg loginForWechat(String openId);
ResultMsg loginForToken(String token);
ResultMsg loginForTelphone(String phone,String code);
}
package com;
public class ResultMsg {
private int code;
private String msg;
private Object data;
public ResultMsg(int code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
package com;
/**
* 注册账号信息
*/
public class Member {
private String username;
private String password;
private String mid;
private String info;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMid() {
return mid;
}
public void setMid(String mid) {
this.mid = mid;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
- adapterv2文件夹
package com.adapterv2.adapters;
import com.adapterv2.ResultMsg;
public abstract class AbstraceAdapter extends PassportService implements ILoginAdapter {
protected ResultMsg loginForRegist(String username, String password){
if(null == password){
password = "THIRD_EMPTY";
}
super.regist(username,password);
return super.login(username,password);
}
}
package com.adapterv2.adapters;
public class PassportService {
/**
* 注册方法
* @param username
* @param password
* @return
*/
public ResultMsg regist(String username,String password){
return new ResultMsg(200,"注册成功",new Member());
}
/**
* 登录的方法
* @param username
* @param password
* @return
*/
public ResultMsg login(String username,String password){
return null;
}
}
package com.adapterv2.adapters;
import com.adapterv2.ResultMsg;
public interface ILoginAdapter {
boolean support(Object object);
ResultMsg login(String id,Object adapter);
}
package com.adapterv2.adapters;
import com.adapterv2.ResultMsg;
/**
* # 适配器模式调用入口—extends AbstraceAdapter
* #abstract class AbstraceAdapter.java
* LoginForQQAdapter.java
*/
public class LoginForQQAdapter extends AbstraceAdapter{
public boolean support(Object adapter) {
return adapter instanceof LoginForQQAdapter;
}
public ResultMsg login(String id, Object adapter) {
if(!support(adapter)){return null;}
//accesseToken
//time
return super.loginForRegist(id,null);
}
}
package com.adapterv2.adapters;
import com.adapterv2.ResultMsg;
public class LoginForTelAdapter extends AbstraceAdapter{
public boolean support(Object adapter) {
return adapter instanceof LoginForTelAdapter;
}
public ResultMsg login(String id, Object adapter) {
return super.loginForRegist(id,null);
}
}
package com.adapterv2.adapters;
import com.adapterv2.ResultMsg;
public class LoginForTokenAdapter extends AbstraceAdapter {
public boolean support(Object adapter) {
return adapter instanceof LoginForTokenAdapter;
}
public ResultMsg login(String id, Object adapter) {
return super.loginForRegist(id,null);
}
}
package com.adapterv2.adapters;
import com.adapterv2.ResultMsg;
public class LoginForWechatAdapter extends AbstraceAdapter{
public boolean support(Object adapter) {
return adapter instanceof LoginForWechatAdapter;
}
public ResultMsg login(String id, Object adapter) {
return super.loginForRegist(id,null);
}
}
package com.adapterv2;
/**
* adapterv2Test
*/
public class Test {
public static void main(String[] args) {
IPassportForThird adapter = new PassportForThirdAdapter();
adapter.loginForQQ("sdfasdfasfasfas");
}
}
package com.adapterv2;
public interface IPassportForThird {
ResultMsg loginForQQ(String openId);
ResultMsg loginForWechat(String openId);
ResultMsg loginForToken(String token);
ResultMsg loginForTelphone(String phone, String code);
}
package com.adapterv2;
import com.adapterv2.adapters.*;
/**
* # Test调用入口
* // 小作坊适配器模式——(反射改造)——调用入口
* abstract class AbstraceAdapter extends PassportService implements ILoginAdapter
* class LoginForQQAdapter extends AbstraceAdapter
* private ResultMsg processLogin(String id,Class<? extends ILoginAdapter> clazz){
*/
public class PassportForThirdAdapter implements IPassportForThird {
public ResultMsg loginForQQ(String openId) {
return processLogin(openId, LoginForQQAdapter.class);
}
public ResultMsg loginForWechat(String openId) {
return processLogin(openId, LoginForWechatAdapter.class);
}
public ResultMsg loginForToken(String token) {
return processLogin(token, LoginForTokenAdapter.class);
}
public ResultMsg loginForTelphone(String phone, String code) {
return processLogin(phone, LoginForTelAdapter.class);
}
/**
* // 小作坊适配器模式——(反射改造)——调用入口
* abstract class AbstraceAdapter extends PassportService implements ILoginAdapter
* class LoginForQQAdapter extends AbstraceAdapter
* @param id
* @param clazz
* @return
*/
private ResultMsg processLogin(String id,Class<? extends ILoginAdapter> clazz){
try {
ILoginAdapter adapter = clazz.newInstance();
if (adapter.support(adapter)){
return adapter.login(id,adapter);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.adapterv2;
public class ResultMsg {
private int code;
private String msg;
private Object data;
public ResultMsg(int code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
package com.adapterv2;
/**
* 注册账号信息
*/
public class Member {
private String username;
private String password;
private String mid;
private String info;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMid() {
return mid;
}
public void setMid(String mid) {
this.mid = mid;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
桥接模式(Bridge Pattern)
桥接模式(Bridge Pattern)也称为桥梁模式、接口(Interfce)模式或柄体(Handle and Body)模式,是将抽象部分与它的具体实现部分分离,使它们都可以独立地变化。
通过组合的方式建立两个类之间的联系,而不是继承
属于结构型模式。
-
桥接模式的适用场景
1、在抽象和具体实现之间需要增加更多的灵活性的场景。
2、一个类存在两个(或多个)独立变化的维度,而这两个(或多个)维度都需要独立进行扩展。
3、不希望使用继承,或因为多层继承导致系统类的个数剧增。 -
桥接模式的优点
1、分离抽象部分及其具体实现部分
2、提高了系统的扩展性
3、符合开闭原则
4、符合合成复用原则 -
桥接模式的缺点
1、增加了系统的理解与设计难度
2、需要正确地识别系统中两个独立变化的维度 -
桥接模式相关的设计模式
1、桥接模式和组合模式
2、桥接模式和适配器模式
代码示栗:
- course文件夹
package com.course;
public interface ICourse {
}
package com.course;
public class AbstractCourse implements ICourse {
private INote note;
private IVideo video;
public void setNote(INote note) {
this.note = note;
}
public void setVideo(IVideo video) {
this.video = video;
}
@Override
public String toString() {
return "AbstractCourse{" +
"note=" + note +
", video=" + video +
'}';
}
}
package com.course;
public class JavaCourse extends AbstractCourse {
}
package com.course;
public class PythonCourse extends AbstractCourse {
}
package com.course;
public interface INote {
void edit();
}
package com.course;
public class JavaNote implements INote {
public void edit() {
}
}
package com.course;
public class PythonNote implements INote {
public void edit() {
}
}
package com.course;
public interface IVideo {
}
package com.course;
public class JavaVideo implements IVideo {
}
package com.course;
public class PythonVideo implements IVideo {
}
- message文件夹
package com.message;
public abstract class AbastractMessage {
private IMessage message;
public AbastractMessage(IMessage message) {
this.message = message;
}
void sendMessage(String message,String toUser){
this.message.send(message,toUser);
}
}
package com.message;
public class NomalMessage extends AbastractMessage {
public NomalMessage(IMessage message) {
super(message);
}
}
package com.message;
public class UrgencyMessage extends AbastractMessage {
public UrgencyMessage(IMessage message) {
super(message);
}
void sendMessage(String message, String toUser){
message = "【加急】" + message;
super.sendMessage(message,toUser);
}
public Object watch(String messageId){
return null;
}
}
package com.message;
public interface IMessage {
//发送消息的内容和接收人
void send(String message,String toUser);
}
package com.message;
public class EmailMessage implements IMessage {
public void send(String message, String toUser) {
System.out.println("使用邮件消息发送" + message + "给" + toUser);
}
}
package com.message;
public class SmsMessage implements IMessage {
public void send(String message, String toUser) {
System.out.println("使用短信消息发送" + message + "给" + toUser);
}
}
package com.message;
public class Test {
public static void main(String[] args) {
IMessage message = new SmsMessage();
AbastractMessage abastractMessage = new NomalMessage(message);
abastractMessage.sendMessage("加班申请","王总");
message = new EmailMessage();
abastractMessage = new UrgencyMessage(message);
abastractMessage.sendMessage("加班申请","王总");
// #输出内容:
// 使用短信消息发送加班申请给王总
// 使用邮件消息发送【加急】加班申请给王总
}
}
享元模式(Flyweight Pattern)
享元模式(Flyweight Pattern)又称为轻量级模式,是对象池的一种实现。类似于线程池,线程池可以避免不停的创建和销毁多个对象,消耗性能。提供了减少对象数量从而改善应用所需的对象结构的方式。
宗旨:共享细粒度对象,将多个对同一对象的访问集中起来。
属于结构型模式。
-
享元模式的适用场景
常常应用于系统底层的开发,以便解决系统的性能问题。
系统有大量相似对象、需要缓冲池的场景。 -
享元模式扩展知识
内部状态
外部状态 -
享元模式的优点
减少对象的创建,降低内存中对象的数量,降低系统的内存,提高效率
减少内存之外的其他资源占用 -
享元模式的缺点
关注内、外部状态、关注线程安全问题
使系统、程序的逻辑复杂化 -
享元模式相关的模式
享元模式和代理模式
享元模式和单例模式
代码示栗:
- ticket文件夹
package com.ticket;
public interface ITicket {
void showInfo(String bunk);
}
package com.ticket;
import java.util.Random;
public class TrainTicket implements ITicket {
private String from;
private String to;
private int price;
public TrainTicket(String from, String to) {
this.from = from;
this.to = to;
}
public void showInfo(String bunk) {
this.price = new Random().nextInt(500);
System.out.println(String.format("%s->%s:%s价格:%s 元", this.from, this.to, bunk, this.price));
}
}
package com.ticket;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
class TicketFactory {
private static Map<String, ITicket> sTicketPool = new ConcurrentHashMap<String,ITicket>();
public static ITicket queryTicket(String from, String to) {
String key = from + "->" + to;
if (TicketFactory.sTicketPool.containsKey(key)) {
System.out.println("使用缓存:" + key);
return TicketFactory.sTicketPool.get(key);
}
System.out.println("首次查询,创建对象: " + key);
ITicket ticket = new TrainTicket(from, to);
TicketFactory.sTicketPool.put(key, ticket);
return ticket;
}
}
package com.ticket;
public class Test {
public static void main(String[] args) {
ITicket ticket = TicketFactory.queryTicket("北京西", "长沙");
ticket.showInfo("硬座");
ticket = TicketFactory.queryTicket("北京西", "长沙");
ticket.showInfo("软座");
ticket = TicketFactory.queryTicket("北京西", "长沙");
ticket.showInfo("硬卧");
// #输出内容:
// 首次查询,创建对象: 北京西->长沙
// 北京西->长沙:硬座价格:422 元
// 使用缓存:北京西->长沙
// 北京西->长沙:软座价格:5 元
// 使用缓存:北京西->长沙
// 北京西->长沙:硬卧价格:116 元
}
}
- pool文件夹
package com.pool;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Vector;
public class ConnectionPool {
private Vector<Connection> pool;
private String url = "jdbc:mysql://localhost:3306/test";
private String username = "root";
private String password = "root";
private String driverClassName = "com.mysql.jdbc.Driver";
private int poolSize = 100;
public ConnectionPool() {
pool = new Vector<Connection>(poolSize);
try{
Class.forName(driverClassName);
for (int i = 0; i < poolSize; i++) {
Connection conn = DriverManager.getConnection(url,username,password);
pool.add(conn);
}
}catch (Exception e){
e.printStackTrace();
}
}
public synchronized Connection getConnection(){
if(pool.size() > 0){
Connection conn = pool.get(0);
pool.remove(conn);
return conn;
}
return null;
}
public synchronized void release(Connection conn){
pool.add(conn);
}
}
package com.pool;
import java.sql.Connection;
public class Test {
public static void main(String[] args) {
ConnectionPool pool = new ConnectionPool();
Connection conn = pool.getConnection();
System.out.println(conn);
}
}
- jdk文件夹
package com.integer;
public class IntegerTest {
public static void main(String[] args) {
Integer a = Integer.valueOf(127);
Integer b = 127;
Integer c = Integer.valueOf(128);
Integer d = 128;
System.out.println("a==b:" + (a==b));
System.out.println("c==d:" + (c==d));
// #输出内容:
// a==b:true
// c==d:false
}
}
package com.string;
public class StringTest {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
String s3 = "he" + "llo";
String s4 = "hel" + new String("lo");
String s5 = new String("hello");
String s6 = s5.intern();
String s7 = "h";
String s8 = "ello";
String s9 = s7 + s8;
System.out.println(s1==s2);//true
System.out.println(s1==s3);//true
System.out.println(s1==s4);//false
System.out.println(s1==s9);//false
System.out.println(s4==s5);//false
System.out.println(s1==s6);//true
}
}
组合模式(Composite Pattern)
组合模式(Composite Pattern)也称为整体-部分(Part-Whole)模式,它的宗旨是通过将单个对象(叶子节点)和组合对象(树枝节点)用相同的接口进行表示。
作用:使客户端对单个对象和组合对象保持一致的方式处理。
属于结构型模式。
-
组合模式的适用场景
1、希望客户端可以忽略组合对象与单个对象的差异时;
2、对象层次具备整体和部分,呈树形结构(如树形菜单,操作系统目录结构,公司组织架构等)。 -
组合模式的优点
1、清楚地定义分层次的复杂对象,表示对象的全部或部分层次
2、让客户端忽略了层次的差异,方便对整个层次结构进行控制
3、简化客户端代码
4、符合开闭原则 -
组合模式的缺点
1、限制类型时会较为复杂
2、使设计变得更加抽象
代码示栗:
- transparent文件夹
package com.transparent;
public class Test {
public static void main(String[] args) {
System.out.println("============透明组合模式===========");
CourseComponent javaBase = new Course("Java入门课程",8280);
CourseComponent ai = new Course("人工智能",5000);
CourseComponent packageCourse = new CoursePackage("Java架构师课程",2);
CourseComponent design = new Course("Java设计模式",1500);
CourseComponent source = new Course("源码分析",2000);
CourseComponent softSkill = new Course("软技能",3000);
packageCourse.addChild(design);
packageCourse.addChild(source);
packageCourse.addChild(softSkill);
CourseComponent catalog = new CoursePackage("课程主目录",1);
catalog.addChild(javaBase);
catalog.addChild(ai);
catalog.addChild(packageCourse);
catalog.print();
// #输出内容:
// ============透明组合模式===========
// 课程主目录
// +-Java入门课程 (¥8280.0元)
// +-人工智能 (¥5000.0元)
// +-Java架构师课程
// +--Java设计模式 (¥1500.0元)
// +--源码分析 (¥2000.0元)
// +--软技能 (¥3000.0元)
// Disconnected from the target VM, address: '127.0.0.1:50642', transport: 'socket'
}
}
package com.transparent;
public abstract class CourseComponent {
public void addChild(CourseComponent catalogComponent){
throw new UnsupportedOperationException("不支持添加操作");
}
public void removeChild(CourseComponent catalogComponent){
throw new UnsupportedOperationException("不支持删除操作");
}
public String getName(CourseComponent catalogComponent){
throw new UnsupportedOperationException("不支持获取名称操作");
}
public double getPrice(CourseComponent catalogComponent){
throw new UnsupportedOperationException("不支持获取价格操作");
}
public void print(){
throw new UnsupportedOperationException("不支持打印操作");
}
}
package com.transparent;
import java.util.ArrayList;
import java.util.List;
public class CoursePackage extends CourseComponent {
private List<CourseComponent> items = new ArrayList<CourseComponent>();
private String name;
private Integer level;
public CoursePackage(String name, Integer level) {
this.name = name;
this.level = level;
}
@Override
public void addChild(CourseComponent catalogComponent) {
items.add(catalogComponent);
}
@Override
public String getName(CourseComponent catalogComponent) {
return this.name;
}
@Override
public void removeChild(CourseComponent catalogComponent) {
items.remove(catalogComponent);
}
@Override
public void print() {
System.out.println(this.name);
for(CourseComponent catalogComponent : items){
//控制显示格式
if(this.level != null){
for(int i = 0; i < this.level; i ++){
//打印空格控制格式
System.out.print(" ");
}
for(int i = 0; i < this.level; i ++){
//每一行开始打印一个+号
if(i == 0){ System.out.print("+"); }
System.out.print("-");
}
}
//打印标题
catalogComponent.print();
}
}
}
package com.transparent;
public class Course extends CourseComponent {
private String name;
private double price;
public Course(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String getName(CourseComponent catalogComponent) {
return this.name;
}
@Override
public double getPrice(CourseComponent catalogComponent) {
return this.price;
}
@Override
public void print() {
System.out.println(name + " (¥" + price + "元)");
}
}
- safe文件夹
这里是引用
package com.safe;
class Test {
public static void main(String[] args) {
System.out.println("============安全组合模式===========");
File qq = new File("QQ.exe");
File wx = new File("微信.exe");
Folder office = new Folder("办公软件",2);
File word = new File("Word.exe");
File ppt = new File("PowerPoint.exe");
File excel = new File("Excel.exe");
office.add(word);
office.add(ppt);
office.add(excel);
Folder wps = new Folder("金山软件",3);
wps.add(new File("WPS.exe"));
office.add(wps);
Folder root = new Folder("根目录",1);
root.add(qq);
root.add(wx);
root.add(office);
System.out.println("----------show()方法效果-----------");
root.show();
System.out.println("----------list()方法效果-----------");
root.list();
// #输出内容:
// ============安全组合模式===========
// ----------show()方法效果-----------
// 根目录
// +-QQ.exe
// +-微信.exe
// +-办公软件
// +--Word.exe
// +--PowerPoint.exe
// +--Excel.exe
// +--金山软件
// +---WPS.exe
// ----------list()方法效果-----------
// QQ.exe
// 微信.exe
// 办公软件
}
}
package com.safe;
public abstract class Directory {
protected String name;
public Directory(String name) {
this.name = name;
}
public abstract void show();
}
package com.safe;
import java.util.ArrayList;
import java.util.List;
public class Folder extends Directory {
private List<Directory> dirs;
private Integer level;
public Folder(String name,Integer level) {
super(name);
this.level = level;
this.dirs = new ArrayList<Directory>();
}
@Override
public void show() {
System.out.println(this.name);
for (Directory dir : this.dirs) {
//控制显示格式
if(this.level != null){
for(int i = 0; i < this.level; i ++){
//打印空格控制格式
System.out.print(" ");
}
for(int i = 0; i < this.level; i ++){
//每一行开始打印一个+号
if(i == 0){ System.out.print("+"); }
System.out.print("-");
}
}
//打印名称
dir.show();
}
}
public boolean add(Directory dir) {
return this.dirs.add(dir);
}
public boolean remove(Directory dir) {
return this.dirs.remove(dir);
}
public Directory get(int index) {
return this.dirs.get(index);
}
public void list(){
for (Directory dir : this.dirs) {
System.out.println(dir.name);
}
}
}
package com.safe;
public class File extends Directory {
public File(String name) {
super(name);
}
@Override
public void show() {
System.out.println(this.name);
}
}
门面模式(Facade Pattern)
门面模式(Facade Pattern)又叫外观模式,提供了一个统一的接口,用来访问子系统中的一群接口。
特征:门面模式定义了一个高层接口,让子系统更容易使用。
属于结构型模式
-
门面模式的适用场景
子系统越来越复杂,增加门面模式提供简单接口
构建多层系统结构,利用门面对象作为每层的入口,简化层间调用。 -
门面模式相关的设计模式
1、门面模式和代理模式
2、门面模式和单例模式 -
门面模式与代理模式
门面模式就是特殊的静态代理模式
门面模式:重点是在于封装
静态代理:重点是在增强
不做增强的静态代理就是门面模式
代理:结构型模式
委派:行为型模式,不属于GoF 23 -
门面模式和单例模式
门面模式做成单例,工具包 -
门面模式的优点
1、简化了调用过程,无需深入了解子系统,以防给子系统带来风险。
2、减少系统依赖、松散耦合
3、更好地划分访问层次,提高了安全性
4、遵循迪米特法则,即最少知道原则 -
门面模式的缺点
1、当增加子系统和扩展子系统行为时,可能容易带来未知风险
2、不符合开闭原则
3、某些情况下可能违背单一职责原则
行为型模式
委派模式(Delegate Pattern)
委派模式(Delegate Pattern)又叫委托模式。它的基本作用就是负责任务的调度和任务分配,将任务的分配和执行分离开来。可以看做是一种特殊情况下的静态代理的全权代理。
不属于GOF 23种设计模式之一。
属于行为型模式。
-
委派模式的应用场景
1、委派对象本身不知道如何处理一个任务(或一个请求),把请求交给其它对象来处理。
2、实现程序的解耦。 -
委派模式的优点
通过任务委派能够将一个大型的任务细化,然后通过统一管理这些子任务的完成情况实现任务的跟进,能够加快任务执行的效率。 -
委派模式的缺点
任务委派方式需要根据任务的复杂程度进行不同的改变,在任务比较复杂的情况下可能需要进行多重委派,容易造成紊乱。 -
委派模式和代理模式的区别
1、委派模式是行为型模式,代理模式是结构型模式
2、委派模式注重的是任务派遣,注重结果;代理模式注重的是代码增强,注重过程。
3、委派模式是一种特殊的静态代理,相当于全权代理。
代码示栗:
- simple文件夹
package com.simple;
public class Test {
public static void main(String[] args) {
new Boss().command("海报图",new Leader());
new Boss().command("爬虫",new Leader());
new Boss().command("卖手机",new Leader());
// #输出内容:
// 我是员工B,我擅长平面设计,现在开始做海报图工作
// 我是员工A,我擅长编程,现在开始做爬虫工作
// 这个任务卖手机超出我的能力范围
}
}
package com.simple;
public class Boss {
public void command(String task,Leader leader){
leader.doing(task);
}
}
package com.simple;
import java.util.HashMap;
import java.util.Map;
public class Leader implements IEmployee {
private Map<String,IEmployee> employee = new HashMap<String,IEmployee>();
public Leader(){
employee.put("爬虫",new EmployeeA());
employee.put("海报图",new EmployeeB());
}
public void doing(String task) {
if(!employee.containsKey(task)){
System.out.println("这个任务" +task + "超出我的能力范围");
return;
}
employee.get(task).doing(task);
}
}
package com.simple;
public interface IEmployee {
void doing(String task);
}
package com.simple;
public class EmployeeA implements IEmployee {
protected String goodAt = "编程";
public void doing(String task) {
System.out.println("我是员工A,我擅长" + goodAt + ",现在开始做" +task + "工作");
}
}
package com.simple;
public class EmployeeB implements IEmployee {
protected String goodAt = "平面设计";
public void doing(String task) {
System.out.println("我是员工B,我擅长" + goodAt + ",现在开始做" +task + "工作");
}
}
- mvc文件夹
package com.mvc;
import com.MemberController;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class DispatcherServlet extends HttpServlet {
private Map<String,Method> handlerMapping = new HashMap<String,Method>();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doDispatch(req,resp);
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) {
String url = req.getRequestURI();
Method method = handlerMapping.get(url);
// method.invoke();
}
@Override
public void init() throws ServletException {
try {
handlerMapping.put("/web/getMemeberById.json", MemberController.class.getMethod("getMemberById", new Class[]{String.class}));
}catch (Exception e){
e.printStackTrace();
}
}
}
package com;
public class MemberController {
public void getMemberById(String mid){
}
}
模板方法模式(Template Method Pattern)
模板方法模式(Template Method Pattern)通常又叫模板模式,是指定义一个算法的骨架,并允许子类为其中的一个或者多个步骤提供实现。
模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。
属于行为型设计模式。
-
模板模式的适用场景
1、一次性实现一个算法不变的部分,并将可变的行为留给子类来实现。
2、各子类中公共的行为被提取出来并集中到一个公共的父类中,从而避免代码重复。 -
模板模式的优点
1、利用模板方法将相同处理逻辑的代码放到抽象父类中,可以提高代码的复用性。
2、将不同的代码不同的子类中,通过对子类的扩展增加新的行为,提/间高代码的扩展性。
3、把不变的行为写在父类上,去除子类的重复代码,提供了一个很好的代码复用平台,符合开闭原则。 -
模板模式的缺点
1、类数目的增加,每一个抽象类都需要一个子类来实现,这样导致类的个数增加。
2、类数量的增加,间接地增加了系统实现的复杂度。
3、继承关系自身缺点,如果父类添加新的抽象方法,所有子类都要改一遍。
代码示栗:
- general文件夹
package com.general;
public class Test {
public static void main(String[] args) {
AbstractClass abc = new ConcreteClassA();
abc.templateMehthod();
abc = new ConcreteClassB();
abc.templateMehthod();
// #输出内容:
// ConcreateClassA:step1
// AbstractClass:step2
// AbstractClass:step3
// AbstractClass:step1
// ConcreateClassB:step2
// AbstractClass:step3
}
}
package com.general;
/**
* 抽象模板类
*/
public abstract class AbstractClass {
protected void step1() {
System.out.println("AbstractClass:step1");
}
protected void step2() {
System.out.println("AbstractClass:step2");
}
protected void step3() {
System.out.println("AbstractClass:step3");
}
// 声明为final方法,避免子类覆写==不能重写
public final void templateMehthod() {
this.step1();
this.step2();
this.step3();
}
}
package com.general;
/**
* 具体实现类A
*/
public class ConcreteClassA extends AbstractClass {
@Override
protected void step1() {
System.out.println("ConcreateClassA:step1");
}
}
package com.general;
/**
* 具体实现类B
*/
public class ConcreteClassB extends AbstractClass {
@Override
protected void step2() {
System.out.println("ConcreateClassB:step2");
}
}
- course文件夹
package com.course;
public class Test {
public static void main(String[] args) {
System.out.println("=========架构师课程=========");
JavaCourse java = new JavaCourse();
java.setNeedCheckHomework(false);
java.createCourse();
System.out.println("=========Python课程=========");
PythonCourse python = new PythonCourse();
python.createCourse();
// #输出内容:
// =========架构师课程=========
// 发布预习资料
// 制作课件
// 直播授课
// 上传课后资料
// 布置作业
// =========Python课程=========
// 发布预习资料
// 制作课件
// 直播授课
// 上传课后资料
// 布置作业
}
}
package com.course;
public abstract class AbastractCourse {
public final void createCourse(){
//1、发布预习资料
postPreResoucse();
//2、制作课件
createPPT();
//3、直播授课
liveVideo();
//4、上传课后资料
postResource();
//5、布置作业
postHomework();
if(needCheckHomework()){
checkHomework();
}
}
protected abstract void checkHomework();
//钩子方法
protected boolean needCheckHomework(){
return false;
}
protected void postHomework(){
System.out.println("布置作业");
}
protected void postResource(){
System.out.println("上传课后资料");
}
protected void liveVideo(){
System.out.println("直播授课");
}
protected void createPPT(){
System.out.println("制作课件");
}
protected void postPreResoucse(){
System.out.println("发布预习资料");
}
}
package com.course;
public class JavaCourse extends AbastractCourse {
private boolean needCheckHomework = false;
public void setNeedCheckHomework(boolean needCheckHomework) {
this.needCheckHomework = needCheckHomework;
}
@Override
protected boolean needCheckHomework() {
return this.needCheckHomework;
}
protected void checkHomework() {
System.out.println("检查Java作业");
}
}
package com.course;
public class PythonCourse extends AbastractCourse {
protected void checkHomework() {
System.out.println("检查Python作业");
}
}
- jdbc文件夹
执行顺序
* 1.参数(sql try{方法里的函数
* 2.this.parseResultSet(rs,rowMapper)
* 3.rowMapper.mapRow(rs,rowNum++)
* 4.调用实现接口RowMapper的子类方法public Member mapRow(ResultSet rs, int rowNum) throws Exception {
public final List<?> executeQuery(String sql,RowMapper<?> rowMapper,Object[] values){
package com.jdbc;
import com.dao.MemberDao;
import java.util.List;
public class Test {
public static void main(String[] args) {
MemberDao memberDao = new MemberDao(null);
List<?> result = memberDao.selectAll();
}
}
package com.jdbc.dao;
import com.jdbc.entity.Member;
import javax.sql.DataSource;
import java.sql.ResultSet;
import java.util.List;
public class MemberDao extends JdbcTemplate {
public MemberDao(DataSource dataSource) {
super(dataSource);
}
public List<?> selectAll(){
String sql = "select * from t_member";
return super.executeQuery(sql, new RowMapper<Member>() {
public Member mapRow(ResultSet rs, int rowNum) throws Exception {
Member member = new Member();
//字段过多,原型模式
member.setUsername(rs.getString("username"));
member.setPassword(rs.getString("password"));
member.setAge(rs.getInt("age"));
member.setAddr(rs.getString("addr"));
return member;
}
},null);
}
}
package com.jdbc;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public abstract class JdbcTemplate {
private DataSource dataSource;
public JdbcTemplate(DataSource dataSource) {
this.dataSource = dataSource;
}
/**执行顺序
* 1.参数(sql try{方法里的函数
* 2.this.parseResultSet(rs,rowMapper)
* 3.rowMapper.mapRow(rs,rowNum++)
* 4.调用实现接口RowMapper的子类方法public Member mapRow(ResultSet rs, int rowNum) throws Exception {
* @param sql
* @param rowMapper
* @param values
* @return
*/
public final List<?> executeQuery(String sql,RowMapper<?> rowMapper,Object[] values){
try {
//1、获取连接
Connection conn = this.getConnection();
//2、创建语句集
PreparedStatement pstm = this.createPrepareStatement(conn,sql);
//3、执行语句集
ResultSet rs = this.executeQuery(pstm,values);
//4、处理结果集
List<?> result = this.parseResultSet(rs,rowMapper);
//5、关闭结果集
rs.close();
//6、关闭语句集
pstm.close();
//7、关闭连接
conn.close();
return result;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
private List<?> parseResultSet(ResultSet rs, RowMapper<?> rowMapper) throws Exception {
List<Object> result = new ArrayList<Object>();
int rowNum = 0;
while (rs.next()){
result.add(rowMapper.mapRow(rs,rowNum++));
}
return result;
}
private ResultSet executeQuery(PreparedStatement pstm, Object[] values) throws SQLException {
for (int i = 0; i < values.length; i++) {
pstm.setObject(i,values[i]);
}
return pstm.executeQuery();
}
private PreparedStatement createPrepareStatement(Connection conn, String sql) throws SQLException {
return conn.prepareStatement(sql);
}
private Connection getConnection() throws SQLException {
return this.dataSource.getConnection();
}
}
package com.jdbc;
import java.sql.ResultSet;
public interface RowMapper<T> {
T mapRow(ResultSet rs,int rowNum) throws Exception;
}
package com.jdbc.entity;
public class Member {
private String username;
private String password;
private String nickname;
private int age;
private String addr;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
}
策略模式(Strategy Pattern)
策略模式(Strategy Pattern)也叫政策模式(Policy Pattern),它是将定义的算法家族、分别封装起来,让它们之间可以互相替换,从而让算法的变化不会影响到使用算法的用户。
可以避免多重分支的if…else…和switch语句
属于行为型模式。
-
策略模式的适用场景
1、假如系统中有很多类,而他们的区别仅仅在于他们的行为不同。
2、一个系统需要动态地在几种算法中选择一种。
3、需要屏蔽算法规则。 -
策略模式的优点
1、策略模式符合开闭原则。
2、避免使用多重条件转移语句,如if…else…语句、switch语句
3、使用策略模式可以提高算法的保密性和安全性。 -
策略模式的缺点
1、客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
2、代码中会产生非常多策略类,增加维护难度。
代码示栗:
- promotion文件夹
package com.promotion;
public class Test {
public static void main(String[] args) {
String promotion = "";
// IPromotionStrategy strategy = null;
// PromotionActivity activity = new PromotionActivity(new GroupbuyStrategy());
// activity.execute();
PromotionStrategyFacory.getPromotionKeys();
String promotionKey = "COUPON";
IPromotionStrategy promotionStrategy = PromotionStrategyFacory.getPromotionStrategy(promotionKey);
promotionStrategy.doPromotion();
// #输出内容:
// 使用优惠券抵扣
}
}
package com.promotion;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class PromotionStrategyFacory {
private static Map<String,IPromotionStrategy> PROMOTIONS = new HashMap<String,IPromotionStrategy>();
static {
PROMOTIONS.put(PromotionKey.COUPON,new CouponStrategy());
PROMOTIONS.put(PromotionKey.CASHBACK,new CashbackStrategy());
PROMOTIONS.put(PromotionKey.GROUPBUY,new GroupbuyStrategy());
}
private static final IPromotionStrategy EMPTY = new EmptyStrategy();
private PromotionStrategyFacory(){}
public static IPromotionStrategy getPromotionStrategy(String promotionKey){
IPromotionStrategy strategy = PROMOTIONS.get(promotionKey);
return strategy == null ? EMPTY : strategy;
}
private interface PromotionKey{
String COUPON = "COUPON";
String CASHBACK = "CASHBACK";
String GROUPBUY = "GROUPBUY";
}
public static Set<String> getPromotionKeys(){
return PROMOTIONS.keySet();
}
}
package com.promotion;
public interface IPromotionStrategy {
void doPromotion();
}
package com.promotion;
public class EmptyStrategy implements IPromotionStrategy {
public void doPromotion() {
System.out.println("无优惠");
}
}
package com.promotion;
public class CashbackStrategy implements IPromotionStrategy {
public void doPromotion() {
System.out.println("返现,直接打款到支付宝账号");
}
}
package com.promotion;
public class CouponStrategy implements IPromotionStrategy {
public void doPromotion() {
System.out.println("使用优惠券抵扣");
}
}
package com.promotion;
public class GroupbuyStrategy implements IPromotionStrategy {
public void doPromotion() {
System.out.println("5人成团,可以优惠");
}
}
- pay文件夹
package com.pay.payport;
import java.util.HashMap;
import java.util.Map;
public class PayStrategy {
public static final String ALI_PAY = "AliPay";
public static final String JD_PAY = "JdPay";
public static final String WECHAT_PAY = "WechatPay";
public static final String UNION_PAY = "UnionPay";
public static final String DEFAULT_PAY = ALI_PAY;
private static Map<String,Payment> strategy = new HashMap<String,Payment>();
static {
strategy.put(ALI_PAY,new AliPay());
strategy.put(JD_PAY,new JDPay());
strategy.put(WECHAT_PAY,new WechatPay());
strategy.put(UNION_PAY,new UnionPay());
}
public static Payment get(String payKey){
if(!strategy.containsKey(payKey)){
return strategy.get(DEFAULT_PAY);
}
return strategy.get(payKey);
}
}
package com.payport;
import com.pay.MsgResult;
public abstract class Payment {
public abstract String getName();
//通用逻辑放到抽象类里面实现
public MsgResult pay(String uid, double amount){
//余额是否足够
if(queryBalance(uid) < amount){
return new MsgResult(500,"支付失败","余额不足");
}
return new MsgResult(200,"支付成功","支付金额" + amount);
}
protected abstract double queryBalance(String uid);
}
package com.pay.payport;
public class AliPay extends Payment {
public String getName() {
return "支付宝";
}
protected double queryBalance(String uid) {
return 900;
}
}
package com.pay.payport;
public class JDPay extends Payment {
public String getName() {
return "京东白条";
}
protected double queryBalance(String uid) {
return 500;
}
}
package com.pay.payport;
public class UnionPay extends Payment {
public String getName() {
return "银联支付";
}
protected double queryBalance(String uid) {
return 120;
}
}
package com.pay.payport;
public class WechatPay extends Payment {
public String getName() {
return "微信支付";
}
protected double queryBalance(String uid) {
return 263;
}
}
package com.pay;
import com.pay.payport.PayStrategy;
public class Test {
public static void main(String[] args) {
// #调用入口
Order order = new Order("1","2020031401000323",324.5);
System.out.println(order.pay(PayStrategy.UNION_PAY));
// #输出内容:
// 欢迎使用银联支付
// 本次交易金额为324.5,开始扣款
// MsgResult{code=500, data=余额不足, msg='支付失败'}
}
}
package com.pay;
import com.pay.payport.PayStrategy;
import com.pay.payport.Payment;
public class Order {
private String uid;
private String orderId;
private double amount;
public Order(String uid, String orderId, double amount) {
this.uid = uid;
this.orderId = orderId;
this.amount = amount;
}
public MsgResult pay(){
return pay(PayStrategy.DEFAULT_PAY);
}
/**
* 调用入口
* @param payKey
* @return
*/
public MsgResult pay(String payKey){
Payment payment = PayStrategy.get(payKey);
System.out.println("欢迎使用" + payment.getName());
System.out.println("本次交易金额为" + amount + ",开始扣款");
return payment.pay(uid,amount);
}
}
package com.pay;
public class MsgResult {
private int code;
private Object data;
private String msg;
public MsgResult(int code, String msg, Object data) {
this.code = code;
this.data = data;
this.msg = msg;
}
@Override
public String toString() {
return "MsgResult{" +
"code=" + code +
", data=" + data +
", msg='" + msg + '\'' +
'}';
}
}
责任链模式(Chain of Responsibility Pattern)
责任链模式(Chain of Responsibility Pattern)是将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止。
属于行为型模式。
-
责任链模式的适用场景
1、多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定;
2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求;
3、可动态指定一组对象处理请求。 -
责任链模式的优点
1、将请求与处理解耦;
2、请求处理者(节点对象)只需关注自己感兴趣的请求进行处理即可,对于不感兴趣的请求,直接转发给下一级节点对象;
3、具备链式传递处理请求功能,请求发送者无需知晓链路结构,只需等待请求处理结果;
4、链路结构灵活,可以通过改变链路结构动态地新增或删减责任;
5、易于扩展新的请求处理类(节点),符合开闭原则。 -
责任链模式的缺点
1、责任链太长或者处理时间过长,会影响整体性能;
2、如果节点对象存在循环引用时,会造成死循环,导致系统崩溃;
代码示栗:
- optimiaze文件夹
package com.optimiaze;
public class Test {
public static void main(String[] args) {
MemberService memberService = new MemberService();
memberService.login("China","666");
// #输出内容:
// 用户名和密码不为空,可以往下执行
// 登录成功!
// 允许操作
}
}
package com.optimiaze;
import com.Member;
public abstract class Handler {
protected Handler next;
public void next(Handler next){ this.next = next;}
public abstract void doHandler(Member member);
}
package com.optimiaze;
import com.Member;
import org.apache.commons.lang.StringUtils;
public class MemberService {
public void login(String loginName,String loginPass){
Handler validateHandler = new ValidateHandler();
Handler loginHandler = new LoginHandler();
Handler authHandler = new AuthHandler();
validateHandler.next(loginHandler);
loginHandler.next(authHandler);
validateHandler.doHandler(new Member(loginName,loginPass));
}
}
package com.optimiaze;
import com.Member;
import org.apache.commons.lang.StringUtils;
public class ValidateHandler extends Handler {
public void doHandler(Member member) {
if(StringUtils.isEmpty(member.getLoginName()) ||
StringUtils.isEmpty(member.getLoginPass())){
System.out.println("用户名和密码为空");
return;
}
System.out.println("用户名和密码不为空,可以往下执行");
next.doHandler(member);
}
}
package com.optimiaze;
import com.Member;
public class LoginHandler extends Handler {
public void doHandler(Member member) {
System.out.println("登录成功!");
member.setRoleName("管理员");
next.doHandler(member);
}
}
package com.optimiaze;
import com.Member;
public class AuthHandler extends Handler {
public void doHandler(Member member) {
if(!"管理员".equals(member.getRoleName())){
System.out.println("您不是管理员,没有操作权限");
return;
}
System.out.println("允许操作");
}
}
package com;
public class Member {
private String loginName;
private String loginPass;
private String roleName;
public Member(String loginName, String loginPass) {
this.loginName = loginName;
this.loginPass = loginPass;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getLoginPass() {
return loginPass;
}
public void setLoginPass(String loginPass) {
this.loginPass = loginPass;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
@Override
public String toString() {
return "Member{" +
"loginName='" + loginName + '\'' +
", loginPass='" + loginPass + '\'' +
", roleName='" + roleName + '\'' +
'}';
}
}
- builderchain文件夹
package com.builderchain;
public class Test {
public static void main(String[] args) {
MemberService memberService = new MemberService();
memberService.login("China","666");
// #输出内容:
// 用户名和密码不为空,可以往下执行
// 登录成功!
// 允许操作
}
}
package com.builderchain;
import com.Member;
public abstract class Handler<T> {
protected Handler next;
public void next(Handler next){ this.next = next;}
public abstract void doHandler(Member member);
public static class Builder<T>{
private Handler<T> head;
private Handler<T> tail;
public Builder<T> addHandler(Handler handler){
// do {
if (this.head == null) {
this.head = this.tail = handler;
return this;
}
this.tail.next(handler);
this.tail = handler;
// }while (false);//真正框架中,如果是双向链表,会判断是否已经到了尾部
return this;
}
public Handler<T> build(){
return this.head;
}
}
}
package com.builderchain;
import com.Member;
public class MemberService {
public void login(String loginName,String loginPass){
Handler.Builder builder = new Handler.Builder();
builder.addHandler(new ValidateHandler())
.addHandler(new LoginHandler())
.addHandler(new AuthHandler());
builder.build().doHandler(new Member(loginName,loginPass));
//用过Netty的人,肯定见过
}
}
package com.builderchain;
import com.Member;
import org.apache.commons.lang.StringUtils;
public class ValidateHandler extends Handler {
public void doHandler(Member member) {
if(StringUtils.isEmpty(member.getLoginName()) ||
StringUtils.isEmpty(member.getLoginPass())){
System.out.println("用户名和密码为空");
return;
}
System.out.println("用户名和密码不为空,可以往下执行");
if(null != next) {
next.doHandler(member);
}
}
}
package com.builderchain;
import com.Member;
public class LoginHandler extends Handler {
public void doHandler(Member member) {
System.out.println("登录成功!");
member.setRoleName("管理员");
if(null != next) {
next.doHandler(member);
}
}
}
package com.builderchain;
import com.Member;
public class AuthHandler extends Handler {
public void doHandler(Member member) {
if(!"管理员".equals(member.getRoleName())){
System.out.println("您不是管理员,没有操作权限");
return;
}
System.out.println("允许操作");
}
}
package com;
public class Member {
private String loginName;
private String loginPass;
private String roleName;
public Member(String loginName, String loginPass) {
this.loginName = loginName;
this.loginPass = loginPass;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getLoginPass() {
return loginPass;
}
public void setLoginPass(String loginPass) {
this.loginPass = loginPass;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
@Override
public String toString() {
return "Member{" +
"loginName='" + loginName + '\'' +
", loginPass='" + loginPass + '\'' +
", roleName='" + roleName + '\'' +
'}';
}
}