1 设置模式之单例设计模式
概念:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
(1)饿汉式:
/*** @Description 饿汉式* @author refuel* @version v1.0*/
public class TestSingleton{public static void main(String[] args) {Singleton sing = Singleton.getInstance(); sing.show();}
}
class Singleton { //1、将构造器私有化private Singleton() {}//2、定义创建一个私有对象 private static Singleton Sing = new Singleton();//3、定义公共静态方法返回该类类型的对象 public static Singleton getInstance() {return Sing;}
}
(2)饱汉式,线程不安全
/*** @Description 饱汉式,线程不安全* @author refuel* @version v1.0*/
public class TestSingleton{public static void main(String[] args) {Singleton sing = Singleton.getInstance(); sing.show();}
}
class Singleton { //1、将构造器私有化private Singleton() {}//2、定义创建一个私有对象 private static Singleton Sing;//3、定义公共静态方法返回该类类型的对象 public static Singleton getSingleton() {if(Sing == null) {Sing = new Singleton();}return Sing;}
}
2 设置模式之工厂模式
2.1 简单工厂
简单工厂模式其实不是一个设计模式,反而比较像一种编程习惯。主要我们定义一个非常简单的类主要负责帮我们生产不同的产品。例子如下:
/*** @Description 简单工厂* @author refuel* @version v1.0*/
public class SimpleFactory {//④使用工厂方法,通过传递类型信息来获取实体类的对象public static void main(String[] args) {Factory1 w = new Factory1();//获取Student1Work的对象,并调用他的doWork方法Product1 product = w.getExamples("Student1Work");product.show();//获取Teacher1Work的对象,并调用他的doWork方法Product1 product1 = w.getExamples("Teacher1Work");product1.show();//获取Worker1Work的对象,并调用他的doWork方法Product1 product2 = w.getExamples("Worker1Work");product2.show();}}//①创建一个 Product接口
interface Product1{void show();
}
// ②实现Product 接口的实体类
class Student1 implements Product1 {@Overridepublic void show() {System.out.println("学生学习");}
}
class Teacher1 implements Product1 {@Overridepublic void show() {System.out.println("老师教书育人");}
}
class Worker1 implements Product1 {@Overridepublic void show() {System.out.println("工人建高楼大厦");}
}
//③定义工厂类 生成基于给定信息的实体类的对象
class Factory1 {//使用getExamples方法获取工作性质类型的对象public Product1 getExamples(String workType) {if(workType ==null) {return null;}if(workType.equalsIgnoreCase("Student1Work")) {return new Student1();}else if(workType.equalsIgnoreCase("Teacher1Work")) {return new Teacher1();}else if(workType.equalsIgnoreCase("Worker1Work")) {return new Worker1();}return null;}
}
2.2 工厂方法模式
简单工厂模式有一个缺点是不同的产品需要不同的额外参数的时候,是不支持的,而且如果使用时传递的type、Class出错,将不能得到正确的对象,容错率不高。而多方法的工厂模式为不同产品,提供不同的生产方法,使用时 需要哪种产品就调用该种产品的方法,使用方便、容错率高。
工厂方法模式概念:定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化。工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类
何时使用:主要解决接口选择的问题,我们明确地计划不同条件下创建不同实例时。
/*** @Description 工厂模式* @author refuel* @version v1.0*/
public class FactoryPattern {public static void main(String[] args) {Factory2 s = new StudentFactory2();s.getExamples().show();Factory2 t = new TeacherFactory2();t.getExamples().show();Factory2 w = new WorkerFactory2();w.getExamples().show();}}//①创建一个 Product接口
interface Product2{void show();
}
// ②实现Product 接口的实体类
class Student2 implements Product2 {@Overridepublic void show() {System.out.println("学生学习");}
}
class Teacher2 implements Product2 {@Overridepublic void show() {System.out.println("老师教书育人");}
}
class Worker2 implements Product2 {@Overridepublic void show() {System.out.println("工人建高楼大厦");}
}
//③定义一个工厂接口
interface Factory2 {Product2 getExamples();
}
//④定义一个学生工厂接口
class StudentFactory2 implements Factory2 {public Product2 getExamples() {return new Student2();}
}
//⑤定义一个老师工厂接口
class TeacherFactory2 implements Factory2 {public Product2 getExamples() {return new Teacher2();}
}
//⑥定义一个工人工厂接口
class WorkerFactory2 implements Factory2 {public Product2 getExamples() {return new Worker2();}
}
2.3 抽象工厂模式
为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
抽象工厂模式,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
/*** @Description 抽象工厂模式* @author refuel* @version v1.0*/
public class AbstractFactoryPattern {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {AbstractFactory sbstractFactory = SuperFactory.getFactory("com.refuel.factory.StudentFactory");Product SmallStudent = sbstractFactory.getExamples("com.refuel.factory.SmallStudent");SmallStudent.show();}}//最高级抽象产品,用于抽象工厂的建造方法的返回值
abstract class Product{abstract void show();
}
//学生产品类
abstract class StudentProduct extends Product{}
//小学生产品
class SmallStudent extends StudentProduct{public void show() {System.out.println("小学生");}
}//中学生产品
class MiddleStudent extends StudentProduct{public void show() {System.out.println("小学生");}
}
//老师产品类
abstract class TeacherProduct extends Product{}
//数学老师产品
class MathTeacher extends TeacherProduct{public void show() {System.out.println("数学老师");}
}//历史老师产品
class HistoryTeacher extends TeacherProduct{public void show() {System.out.println("历史老师");}
}//超级工厂类
class SuperFactory {public static AbstractFactory getFactory(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException {Class cl = Class.forName(type);System.out.println("创建工厂" + type);return (AbstractFactory) cl.newInstance();}
}
//抽象工厂类
abstract class AbstractFactory {protected abstract Product getExamples(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException;
}//学生工厂类,覆盖所有学生的生产方法
class StudentFactory extends AbstractFactory{public Product getExamples(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException {Class cl = Class.forName(type);return (StudentProduct)cl.newInstance();}
}
//老师工厂类,覆盖所有老师的生产方法
class TeacherFactory extends AbstractFactory{public Product getExamples(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException {Class cl = Class.forName(type);return (TeacherProduct)cl.newInstance();}
}
2.4 简单工厂模式,工厂模式与抽象工厂模式的比较
简单工厂模式:(1)优点:工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。(2)缺点:没有遵守开放—封闭原则(开放接口,封闭修改)。如果将来需要添加一个产品,那么,在简单工厂模式中,就必须在简单工厂类中添加相应的判断语句,这对程序的扩展本身就不利。
工厂模式:(1)优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。(2)缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
抽象工厂模式:(1)优点:能够从多个产品族的多个产品中,简洁的获取想要的具体产品。解决了工厂模式中的不符合开闭原则的问题(增加新的产品时候,不修改工厂,而是增加工厂)。(2)缺点:产品族扩展比较困难,要增加一个系列的某一产品,要增加具体的产品类,还要增加对应的工厂类(或者修改对应产品族的工厂类)。产品族难扩展,产品等级易扩展。】
3 代理模式
提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。如果需改别人写好的代码时,可以通过代理的方式来扩展该方法。
3.1 静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。
/*** @Description 静态代理* @author refuel* @version v1.0*/
public class TestProxy {public static void main(String[] args) {//客户租房子,找代理ProcyObject proxy = new ProcyObject(new SubjectImpl());proxy.action();}
}
//接口
interface Subject{void action();
}
//中介(代理)
class ProcyObject implements Subject {//中介和业主有关系,所以定义关联关系SubjectImpl subject = null;public ProcyObject(SubjectImpl subject) {this.subject = subject;}@Overridepublic void action() {//调用业主的方法,自己没有subject.action();}}
//业主
class SubjectImpl implements Subject{@Overridepublic void action() {System.out.println("业主的房子");}}
3.2 动态代理
动态代理也叫做:JDK代理,接口代理。代理对象不需要实现接口,但是目标对象一定要实现接口。代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)。
代理类所在包:java.lang.reflect.Proxy,JDK代理使用newProxyInstance方法。
/*** @Description 动态代理* @author refuel* @version v1.0*/
public class DynamicProxy {public static void main(String[] args) {//目标对象Subject1 s = new SubjectImpl1();//给目标对象创建代理对象,内存中动态生成的代理对象Subject1 proxy = (Subject1)new ProxyFactory(s).getProxyInstance();proxy.action();}
}interface Subject1 {void action();
}/*** @Description 业主类* @author refuel* @version v1.0*/
class SubjectImpl1 implements Subject1 {@Overridepublic void action() {System.out.println("业主的房子");}}/*** @Description 代理工厂类* @author refuel* @version v1.0*/
class ProxyFactory {// 中介和业主有关系,所以定义关联关系,来维护一个目标对象Object subject = null;public ProxyFactory(Object subject) {this.subject = subject;}// 给目标对象生成一个代理对象public Object getProxyInstance() {// ClassLoader loader:指定当前对象使用类加载器,获取类加载器的方法是固定的// Class<?>[] interfaces:目标对象实现的接口类型,使用泛型方式确认// InvocationHandler h:事件处理,执行目标对象时,会触发事件处理器的方法,会把当前执行的目标对象作为的方法作为参数传入return Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("开始事务");// 执行目标对象方法Object invokeValue = method.invoke(subject, args);System.out.println("提交事务");return invokeValue;}});}
}
3.3 Cglib代理
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。静态代理和动态代理模式都是要求目标对象实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理。
/*** @Description Cglib类* @author refuel* @version v1.0*/
public class CglibProxy {public static void main(String[] args) {//目标对象SubjectImpl2 target = new SubjectImpl2();//代理对象SubjectImpl2 proxy = (SubjectImpl2)new ProxyFactory(target).getProxyInstance();//执行代理对象的方法proxy.action();}
}
/*** @Description 业主类,目标对象,没有实现任何接口* @author refuel* @version v1.0*/
class SubjectImpl2 {public void action() {System.out.println("业主的房子");}
}
/*** @Description Cglib子类代理工厂,对SubjectImpl2在内存中动态创建一个子类对象* @author refuel* @version v1.0*/
class ProxyFactory implements MethodInterceptor{// 中介和代理有关系,所以定义关联关系,来维护一个目标对象Object subject = null;public ProxyFactory(Object subject) {this.subject = subject;}// 给目标对象创建一个代理对象public Object getProxyInstance() {//1.工具类Enhancer en = new Enhancer();//2.设置父类en.setSuperclass(subject.getClass());//3.设置回调函数en.setCallback(this);//4.创建子类(代理对象)return en.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("开始");//执行目标对象的方法Object returnValue = method.invoke(subject, args);System.out.println("提交");return returnValue;}}
2.4 静态代理,动态代理,Cglib代理的比较
静态代理:(1)优点:可以做到在不修改目标对象的功能前提下,对目标功能扩展.。(2)缺点:因为目标对象要与代理对象实现一样的接口,所以会产生很多的代理类,导致类太多。接口增加方法,目标对象与代理对象都要进行维护。
动态代理:(1)优点:由于java封装了newProxyInstance这个方法的实现细节,所以使用起来非常方便。(2)缺点:静态代理和JDK代理有一个共同的缺点,就是目标对象必须实现一个或多个接口
Cglib代理:(1)优点:目标对象与代理对象都不用实现接口。(2)缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。
在Spring的AOP编程中,如果加入容器的目标对象有实现接口,用JDK代理,如果目标对象没有实现接口,用Cglib代理
4 策略模式(Strategy Pattern)
4.1 什么是策略模式
针对一组算法,将每一种算法(策略类)都封装到具有共同接口的独立类中,从而他们可以相互替换,可以在不影响客户端的情况下发生改变,从而改变不同的功能。
一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
特点:封装变化的概念;面向接口编程(编程中使用接口而不是使用具体的实现类)。
组成部分:(1)抽象策略角色:是抽象的角色,一般使用接口或抽象类实现,如Comparator接口;
(2)具体策略角色:包装了具体的算法和行为,如一组实现了Comparator接口的实现类;
(3)环境角色:内部有一个抽象角色的引用,给客户端调用,如TreeSet类,内部一定有一个策略类的一个成员变量,这样在创建TreeSet对象的时候可以接收向它传递的具体的策略类。
4.2 为什么使用策略模式
在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。算法可以自由切换,扩展良好;不过策略类会增多,还要对外暴露。
4.3 什么情况下可以使用
(1)如果一个系统中有很多的类,他们之间的区别是他们的行为不同,就可以用策略模式让一个对象在那么多的行为中选择一种;
(2)一个系统需要动态的在几种算法中实现一种。
如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
4.4 案例
实现List集合增删查的功能
编写步骤:(1)定义抽象策略角色(定义一个策略对象的公共接口);(2)编写具体策略角色(实现抽象策略角色这个公共接口);(3)定义环境变量(内部一定要持有一个策略类的引用)。
(1) 定义抽象策略角色:
/*** @Description 定义抽象策略角色* @author refuel* @version v1.0*/
public interface AbstarctStrategy<T> {//实现对List集合的操作public Boolean handle(List<T> list,T t);
}
(2)编写具体策略角色
/*** @Description 定义增加策略* @author refuel* @version v1.0*/
public class AddStrategy<T> implements AbstarctStrategy<T> {//实现handle方法,完成增加元素操作@Overridepublic Boolean handle(List<T> list, T t) {return list.add(t);}}/*** @Description 定义删除策略* @author refuel* @version v1.0*/
public class RemoveStrategy<T> implements AbstarctStrategy<T> {//实现handle方法,完成删除元素操作@Overridepublic Boolean handle(List<T> list, T t) {return list.remove(t);}}/*** @Description 定义查询策略* @author refuel* @version v1.0*/
public class QueryStrategy<T> implements AbstarctStrategy<T> {//实现handle方法,完成查看元素是否存在操作@Overridepublic Boolean handle(List<T> list, T t) {return list.contains(t);}}
(3)定义环境变量
/*** @Description 环境角色* @author refuel* @version v1.0*/
public class Environment<T> {//策略类的引用private AbstarctStrategy<T> strategy;public Environment(AbstarctStrategy<T> strategy) {this.strategy = strategy;}public Boolean handleList(List<T> list,T t) {return strategy.handle(list, t);}
}
(4)测试
/*** @Description 测试类* @author refuel* @version v1.0*/
public class Test {public static void main(String[] args) {Environment<Integer> en = new Environment<>(new AddStrategy<Integer>());List<Integer> arrList = Arrays.asList(10,20,30,40,50);List<Integer> list = new ArrayList<>(arrList);en.handleList(list, 60);for (Integer i : list) {System.out.print(i + " "); //运行结果 10 20 30 40 50 60 }}
}