设计模式自学笔记002_Real(建造者模式、代理模式)
一、建造者模式(生成器模式)
当我们在创建类的实例化对象的时候,有的时候需要设置类的初始值,一般用构造器进行设置,但是,当一个类的初始值比较多的时候,我们的构造器里面的参数就会比较多,现在出现一种情况,就是我在创建实例化对象的时候不需要将这个类里面的变量全部初始化一遍,只需要设置几个就行了,那么第一个想到的就是多创建几个构造器,每一个构造器都根据需要只初始化几个变量,那么这样的话类内部的变量一旦太多,就会需要创建非常多的构造器,给程序员造成不必要的麻烦,而且如果现在又出现一个情况就是我需要初始化的变量需要按照一定的规则进行初始化呢,构造器只能一次性将变量全部构造,而不能按照特定的顺序来,所以建造者设计模式(生成器设计模式)就应运而生。
比如现在有一个类,名字叫做Computer,他有很多变量,比如键盘类KeyBoard,鼠标类Mouse,显示器类Screen等等。
我们在类中将所有的变量的getter()函数和setter()函数都创建之后,我们再类的内部再加一个内部类Builder,然后在里面创建一个Computer类的对象computer,然后对Computer类中的每一个参数都设置一个set函数,让我们可以随意调用,然后最后加一个build()返回computer对象,这样我们在使用这个类的时候,在初始化创建的过程中就可以随意按照我们需要的选择和需要的顺序来创建实例化对象computer。
我们将这个作为一个和例子来实现一下。
public class BuilderDesign {
public static void main(String[] args) {
Computer.Builder builder = new Computer.Builder();
KeyBoard keyBoard = new KeyBoard();
Mouse mouse = new Mouse();
Screen screen = new Screen();
CPU cpu = new CPU();
Computer computer = builder.buildKeyBoard(keyBoard).buildCPU(cpu).buildScreen(screen).buildMouse(mouse).build();
computer.getKeyBoard().print();
computer.getCpu().print();
computer.getScreen().print();
computer.getMouse().print();
}
}
//创造者设计模式
class Computer{
private KeyBoard keyBoard = null;
private Mouse mouse = null;
private Screen screen = null;
private CPU cpu = null;
public KeyBoard getKeyBoard() {
return keyBoard;
}
public void setKeyBoard(KeyBoard keyBoard) {
this.keyBoard = keyBoard;
}
public Mouse getMouse() {
return mouse;
}
public void setMouse(Mouse mouse) {
this.mouse = mouse;
}
public Screen getScreen() {
return screen;
}
public void setScreen(Screen screen) {
this.screen = screen;
}
public CPU getCpu() {
return cpu;
}
public void setCpu(CPU cpu) {
this.cpu = cpu;
}
public static class Builder{
private final Computer computer = new Computer();
public Builder buildKeyBoard(KeyBoard keyBoard){
computer.setKeyBoard(new KeyBoard());
return this;
}
public Builder buildMouse(Mouse mouse){
computer.setMouse(new Mouse());
return this;
}
public Builder buildScreen(Screen screen){
computer.setScreen(new Screen());
return this;
}
public Builder buildCPU(CPU cpu){
computer.setCpu(new CPU());
return this;
}
public Computer build(){
return computer;
}
}
}
//Computer类中用到的变量类
class KeyBoard{
public void print(){
System.out.println("键盘");
}
}
class Mouse{
public void print(){
System.out.println("鼠标");
}
}
class Screen{
public void print(){
System.out.println("屏幕");
}
}
class CPU{
public void print(){
System.out.println("CPU处理器");
}
}
目前由于技术很成熟,我们通常可以利用IDEA的插件生成Builder内部类,插件名字叫做:Builder Generator,
然后我们还可以直接使用注解就能实现建造者设计模式,只要在类的上部加上@Builder
的注解即可,当然需要导入相应的包,
import lombok.Builder;
这个包需要下载,直接在类的上方写上@Builder,然后Alt+Enter就可以导入相应的包。
import lombok.Builder;
public class BuilderDesign02 {
public static void main(String[] args) {
Computer1.Computer1Builder builder = new Computer1.Computer1Builder();
Computer1 computer1 = builder.CPU("CPU").KeyBoard("键盘").Mouse("鼠标").Screen("屏幕").build();
System.out.println(computer1.getKeyBoard());
System.out.println(computer1.getMouse());
System.out.println(computer1.getCPU());
System.out.println(computer1.getScreen());
}
}
@Builder //直接在类的上面加上@Builder注解即可
class Computer1{
private String KeyBoard;
private String Mouse;
private String CPU;
private String Screen;
public String getKeyBoard() {
return KeyBoard;
}
public String getMouse() {
return Mouse;
}
public String getCPU() {
return CPU;
}
public String getScreen() {
return Screen;
}
}
二、静态代理设计模式
静态代理模式主要的额作用是为了能够让类中的方法进行拓展,比如:我们现在有一个类,类中有一个方法,是已经写好的,但是现在我们需要对类中的方法进行拓展,需要让该方法能够实现其他的功能,但是基于开闭原则,我们不能对方法直接进行修改,那么相当于修改代码了,这是不允许的,所以我们最先想到的就是新建一个类,然后继承我们需要修改的类,重写需要修改的方法,直接添加我们需要此u该的代码,并调用父类的该方法即可,具体代码实现如下:
public class ProxyDesign001 {
public static void main(String[] args) {
Phone iphone = new PhoneProxy("HuaWei");
iphone.use();
}
}
//需要修改的类,随着科技的进步,手机不但能打电话,还能玩游戏,看电影、上网
class Phone{
private String phoneType;
public Phone(String phoneType) {
this.phoneType = phoneType;
}
public String getPhoneType() {
return phoneType;
}
public void use(){
System.out.println("用" + phoneType + "手机打电话");
}
}
class PhoneProxy extends Phone{
public PhoneProxy(String phoneType) {
super(phoneType);
}
@Override
public void use() {
System.out.println("用"+super.getPhoneType()+"手机上网");
super.use();
System.out.println("用"+super.getPhoneType()+"手机看电影");
System.out.println("用"+super.getPhoneType()+"手机玩游戏");
}
}
输出结果:
用HuaWei手机上网
用HuaWei手机打电话
用HuaWei手机看电影
用HuaWei手机玩游戏
然后还有第二种方法,那就是实现相同的接口来实现方法的增强,我们首先定义一个接口Phone,然后让我们需要修改的类和代理类都实现这个接口,然后定义其中的方法,就可以对方法进行拓展,具体的代码实现如下。
public class ProxyDesign002 {
public static void main(String[] args) {
Phone phone = new Proxy();
phone.use();
}
}
//需要实现的接口
public interface Phone {
void use();
}
//需要方法拓展的类
class XiaoMiPhone implements Phone{
private String PhoneType;
public XiaoMiPhone(String phoneType) {
PhoneType = phoneType;
}
public String getPhoneType() {
return PhoneType;
}
public void setPhoneType(String phoneType) {
PhoneType = phoneType;
}
@Override
public void use() {
System.out.println("用"+PhoneType+"手机打电话");
}
}
//代理类
class Proxy implements Phone{
private XiaoMiPhone phone = new XiaoMiPhone("Redmi K40");
@Override
public void use() {
System.out.println("用"+phone.getPhoneType()+"手机上网");
phone.use();
System.out.println("用"+phone.getPhoneType()+"手机看电影");
System.out.println("用"+phone.getPhoneType()+"手机打游戏");
}
}
输出结果:
用Redmi K40手机上网
用Redmi K40手机打电话
用Redmi K40手机看电影
用Redmi K40手机打游戏
三、动态代理模式
动态代理的角色和静态代理是相同的。
动态代理的代理类是代码动态生成的,二静态代理是代理类需要我们手写
动态代理与静态代理一样,分类两类:基于接口的动态代理和基于类的动态代理
基于接口的动态代理是JDK内置的,基于类的动态代理需要一个第三方的框架——cglid
1、JDK原生的动态代理
需要了解两个类Proxy和InvocationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyDesign003 {
public static void main(String[] args) {
//参数的设置
//1、当前的classLoader()
//2、需要代理对象实现的接口
//3、InvocationHandler
Phone proxy = (Phone) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[]{Phone.class},
new ApplePhoneInvocationHandler(new ApplePhone("Redmi K40")));
proxy.use();
}
//内部静态类
private static class ApplePhoneInvocationHandler implements InvocationHandler{
private final Phone Iphone;
public ApplePhoneInvocationHandler(Phone iphone) {
this.Iphone = iphone;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("用手机上网");
System.out.println("用手机看电影");
System.out.println("用手机打游戏");
method.invoke(Iphone);
return null;
}
}
}
//代理对象需要实现的接口
public interface Phone {
void use();
}
//需要方法拓展的类
class ApplePhone implements Phone {
private String PhoneType;
public ApplePhone(String phoneType) {
PhoneType = phoneType;
}
public String getPhoneType() {
return PhoneType;
}
public void setPhoneType(String phoneType) {
PhoneType = phoneType;
}
@Override
public void use() {
System.out.println("用"+PhoneType+"手机打电话");
}
}
2、基于cglib的动态代理
略(我懒)