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 {
@Override
public void show() {
System.out.println("学生学习");
}
}
class Teacher1 implements Product1 {
@Override
public void show() {
System.out.println("老师教书育人");
}
}
class Worker1 implements Product1 {
@Override
public 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 {
@Override
public void show() {
System.out.println("学生学习");
}
}
class Teacher2 implements Product2 {
@Override
public void show() {
System.out.println("老师教书育人");
}
}
class Worker2 implements Product2 {
@Override
public 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;
}
@Override
public void action() {
//调用业主的方法,自己没有
subject.action();
}
}
//业主
class SubjectImpl implements Subject{
@Override
public 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 {
@Override
public 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() {
@Override
public 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();
}
@Override
public 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方法,完成增加元素操作
@Override
public 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方法,完成删除元素操作
@Override
public 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方法,完成查看元素是否存在操作
@Override
public 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
}
}
}