单例设计模式

解释:在开发中,当一个类完全不需要有多个实例时,可以使用单例模式来保证一个类只有一个对象。 实际操作为 私有化构造函数

如 票务系统,要保证票数始终同步,卖票的对象可以使用单例模式

  • 饿汉模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SingletonDemo1 {

//饿汉单例模式,在声明变量的时候就直接实例化对象了
//私有化构造函数
private SingletonDemo1() {
}
//创建实例,并私有化
private static SingletonDemo1 instance = new SingletonDemo1();

//将实例返回
public static SingletonDemo1 getInstance(){
return instance;
};

}
  • 懒汉模式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class SingletonDemo2 {
//懒汉单例模式,先声明对象,外部调用且未产生实例对象的时候才创建实例,相比于饿汉模式,不会产生垃圾对象
//私有化构造函数
private SingletonDemo2() {
}
//创建实例,并私有化
private static SingletonDemo2 instance = null;

//将实例返回(可加入synchronized来保证线程安全)
public static SingletonDemo2 getInstance(){
if (instance == null) {
instance = new SingletonDemo2();
}
return instance;
}

}

工厂设计模式

解释:像工厂一样,统一提供产品(实例对象)

工厂设计模式要素: 产品模板 做产品的设备 工厂 进行生产

产品模板

1
2
3
4
5
6
public interface ProductModel {

//创建产品模板
ProductModel DOProductModel();

}

制造做产品的设备

1
2
3
4
5
6
7
public class MakeProduct1 implements ProductModel{
@Override
public ProductModel DOProductModel() {
System.out.println("第一种产品");
return this;
}
}
1
2
3
4
5
6
7
8
public class MakeProduct2 implements ProductModel{

@Override
public ProductModel DOProductModel() {
System.out.println("第二种产品");
return this;
}
}
1
2
3
4
5
6
7
8
public class MakeProduct3 implements ProductModel{

@Override
public ProductModel DOProductModel() {
System.out.println("第三种产品");
return this;
}
}

将设备放入工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ProductFactory {

public ProductModel MakeProduct(String productname){

//创建产品生产设备,根据传入产品名生产产品
if("product1".equals(productname)){
return new MakeProduct1().DOProductModel();
}else if("product2".equals(productname)){
return new MakeProduct2().DOProductModel();
}else if("product3".equals(productname)){
return new MakeProduct3().DOProductModel();
}else{
return null;
}
}
}

客户下订单生产

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MainTest {

public static void main(String[] args) {

//创建工厂对象
ProductFactory productFactory = new ProductFactory();

//创建产品1
ProductModel product1 = productFactory.MakeProduct("product1");
//创建产品2
ProductModel product2 = productFactory.MakeProduct("product2");
//创建产品3
ProductModel product3 = productFactory.MakeProduct("product3");
}
}

代理模式

  • 代理的作用1:除了当前类的功能以外,添加其它的功能

注:解决疑问,为什么不在原来的类中直接添加功能
答:java一直实行单一功能编程,功能越少,改动的几率就越小,如果在本类中进行功能的添加改变,当增加的功能需要更改时,就要在本类中进行查找,而该类添加的方法太多在修改时容易出错

  • 代理的作用2:控制其它类对该类的访问,使其它类无法对基类进行更改

注:解决疑问,继承也不能对基类进行更改,为什么要出现代理呢
答:在子类中使用方法时,对象点方法名会暴露基类中有的方法,而如果使用了代理后,可以将基类的方法封装至代理类创建的方法中,在其它类 创建代理类的对象点方法名时就只能看到代理类的方法,对基类的方法就进行了保护
理解即提取基类的一部分方法放在代理类中,新类只能看到代理类的方法

  • 分类静态代理和动态代理

静态代理和动态代理的区别是,静态代理是 有确定的要代理的类
动态代理没有确定的要代理的类,是使用泛化方式写的,相当于将创建代理这种直接交给机器处理(aop就是使用动态代理,原理就在这)

静态代理

举例1

注:例1是网上流传的静态代理,例2是java思想编程上的代理,我偏向于例2,因为例1在测试类依然会创建基类的对象,也就能得到基类的其它方法,并不能满足 对基类访问控制

  • 基类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Master implements Sell{
//委托类、基类
//这个类 理解:master自己要做的事情
@Override
public void GiveGoods() {
System.out.println("拿出货物");
}

@Override
public void GetMoney() {
System.out.println("收钱");
}

//老板的另外功能进货
public void GetGoods() {
System.out.println("进货");
}
}
  • 先创建接口
1
2
3
4
5
public interface Sell {
//为了创建一个相同格式的代理类而创建的一个接口
void GiveGoods();
void GetMoney();
}
  • 创建代理类将基类方法封装至代理类中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Worker implements Sell{

//创建一个Sell类型的worker
private Sell worker;

//重写构造函数,初始化worker,传入master对象,教worker如何工作
public Worker(Sell master) {
this.worker = master;
}

//这个类的理解,招一个员工worker,master教会worker怎么进行销售,且需要他去进行产品讲解和做账目结算
//代理类的作用是在不去修改委托类的基础上对其方法进行改写
@Override
public void GiveGoods() {
//添加需要添加的功能
System.out.println("给产品做讲解");
//将基类的方法封装至代理类的方法中
this.worker.GiveGoods();
}

@Override
public void GetMoney() {
//将基类的方法封装至代理类中
this.worker.GetMoney();
//添加需要添加的功能
System.out.println("做账目结算");
}

}
  • 测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Main {

//测试类
public static void main(String[] args) {
//创建一个老板对象
Master m = new Master();
//创建一个员工对象,把老板对象的技能交给员工
Worker W = new Worker(m);
//员工做老板规定的工作
W.GiveGoods();
W.GetMoney();
}

}

举例2

  • 基类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SpaceShipControls {
//这是一个控制器类
void up(int x) {
System.out.println("向上移动"+x+ "m");
};
void down(int x) {
System.out.println("向下移动"+x+ "m");
};
void left(int x) {
System.out.println("向左移动"+x+ "m");
};
void right(int x) {
System.out.println("向右移动"+x+ "m");
};
}
  • 代理类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class SpaceShipDelegation {

//创建一个控制器的对象
private SpaceShipControls control = new SpaceShipControls();

//将控制器的功能赋予代理飞船
public void up(int x) {
control.up(x);
};
public void down(int x) {
control.down(x);
};
public void left(int x) {
control.left(x);
};
public void right(int x) {
control.right(x);
};

}
  • 测试类
1
2
3
4
5
6
7
8
9
10
public class Main {

//测试类
public static void main(String[] args) {

SpaceShipDelegation protector = new SpaceShipDelegation();
protector.up(100);
}

}

举例3(完全理解的举例)

  • 基类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class RealClass implements publicInterface{

/*
* 这是基类
*/

@Override
public void Dosth() {
System.out.println("基类做一些事情");
}

@Override
public void DosthElse(String arg) {
System.out.println("基类做一些其它的事");
}

}
  • 接口
1
2
3
4
5
public interface publicInterface {
//基于基类方法创建一个接口,方便创建的代理类能够与基类类型相同
void Dosth();
void DosthElse(String arg);
}
  • 代理类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class ProxyClass implements publicInterface{

/*
* 这是代理类实现与基类相同的接口
*/

//给代理类创建一个对象
private publicInterface piface;

//通过构造器将基类的对象传给代理类的对象
public ProxyClass(publicInterface Proxyiface) {
//将基类的对象赋予代理类中
this.piface = Proxyiface;
}

/*
* 下面两个方法是对基类的两个方法进行改写
*/
@Override
public void Dosth() {
System.out.println("代理类做Dosth之前做额外的事");
//将基类的方法放在代理类的方法中 解决问题:为什么piface可以点出基类的方法,在构造方法中将基类对象赋给了代理类
piface.Dosth();
System.out.println("代理类做Dosth之后做额外的事");
}

@Override
public void DosthElse(String arg) {
System.out.println("代理类做DosthElse之前做额外的事");
//同上
piface.DosthElse(arg);
System.out.println("代理类做DosthElse之后做额外的事");
}

}

  • 测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Test {
/*
* 这是测试类
*/

//此方法是为了方便下面main方法传入什么对象更加直观
public static void consumer(publicInterface newiface) {
newiface.Dosth();
newiface.DosthElse("传入的参数");
}

public static void main(String[] args) {
//使用基类对象,使用方法
consumer(new RealClass());
//使用代理类对象,使用方法(将基类的对象传给代理类的对象)
consumer(new ProxyClass(new RealClass()));
}

}

动态代理

举例(对照前面的静态代理)

注:比较于静态代理其实就是一个泛化,静态代理是程序员自己创建代理类,动态代理是自动生成,所以就应该能对所有的类有作用,所以 前面静态代理例子与下面的动态代理例子不同的地方就是处理泛化的问题。实际就是实现动态代理的接口的invoke方法

  • 基类(基类和接口都是使用前面静态代理一模一样的,方便对照理解)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class RealClass implements publicInterface{

/*
* 这是基类
*/

@Override
public void Dosth() {
System.out.println("原类做一些事情");
}

@Override
public void DosthElse(String arg) {
System.out.println("原类做一些其它的事");
}

}
  • 接口类
1
2
3
4
5
public interface publicInterface {
//基于基类方法创建一个接口,方便创建的代理类能够与基类类型相同
void Dosth();
void DosthElse(String arg);
}
  • 代理类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class DynamicProxyClass implements InvocationHandler{

//为动态代理创建类一个容器,因为不知道基类是什么就使用object作为基类和代理类的共同 类型 ,静态代理这里是写的基类和代理类的都实现的同一个接口
private Object dynamicproxy;

//用proxies来指代需要被代理的类对象,然后将其赋值给动态代理类对象
public DynamicProxyClass(Object proxies) {
this.dynamicproxy = proxies;
}

//这个方法的作用是将基类类中的方法进行分别封装至代理类对应的方法中 可以对照静态代理的 对基类方法进行改写的类 由于动态代理的类是未知的,所以使用invoke这个方法来表示未知的基类中的方方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("这里可以做对基类方法执行前添加其它功能,如获取时间");
//这个用来指代基类的方法,其中proxy是前面的代理对象,args是参数列表,如果不想进行改写的话可以直接下面返回method.invoke(dynamicproxy, args)
//invoke方法中的第一个参数是 所代理类的对象,第二个参数是 所代理的方法的参数列表
Object object = method.invoke(dynamicproxy, args);
System.out.println("这里可以做对基类方法执行后添加其它功能,如打印日志");
return object;
}

}
  • 测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Test {

//此方法是为了方便下面main方法传入什么对象更加直观
public static void consumer(publicInterface newiface) {
newiface.Dosth();
newiface.DosthElse("传入的参数");
}

public static void main(String[] args) {
//这两步时直接执行基类,real是基类对象
RealClass real = new RealClass();
consumer(real);
//这里是使用newProxyInstance方法创建代理类的对象 取个名字newiface,前面的(publicInterface)强转是前面用object来代替的 基类和代理类的共同接口
//publicInterface是接口作为 代理类对象的类型,newProxyInstance中传入的值获得一个类加载器(通常是获得已经被加载的加载器,这里是获取接口的加载器),第二个是接口,第三个是初始化动态代理类,使用其构造方法
//理解 正常的创建类的对象是 publicInterface newiface = new DynamicProxyClass(real),但是动态代理类是实现的InvocationHandler而不是 前面基类实现的那个接口,所以将两个结合起来,静态代理这里是直接前面那样写的
publicInterface newiface = (publicInterface) Proxy.newProxyInstance(publicInterface.class.getClassLoader(), new Class[] {publicInterface.class}, new DynamicProxyClass(real));
consumer(newiface);
}

}