八股 Java进阶

注解

注解

@Override 类似一个标签, 作用在方法上, 表示此方法是父类中重写而来的.

注解是java中的标准, 可以用在类, 方法, 变量, 参数成员上

在编译期间, 会被编译到字节码文件中, 运行是通过反射机制获得注解内容, 进行解析.

内置注解

java中内定的注解

例如@Override

@Deprecated -标记过时方法. 如果使用该方法, 会报编译警告.

@SuppressWarnings - 指示编译器去忽略注解中声明的警告

@Functionallnterface 用于指示被修饰的接口是函数式接口.

元注解

注解的注解, 用于定义注解的注解

@Target({TYPE, FIELD, METHOD})  定义此注解应该作用在哪些成员目标上(定义注解在哪些位置有效)
@Retention()  定义注解在什么时候生效
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)

自定义一个注解

定义注解

使用注解

解析注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNull {

	//注解属性
	String message() default "";
	
	int minlength() default 0;
	
	String lengthmessage() default "";
}

public class User {
	
	private int num=0;

	@NotNull(message = "姓名不能为空",minlength = 3,lengthmessage = "姓名长度不能小于3位")
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

}
public class User {
	
	private int num=0;

	@NotNull(message = "姓名不能为空",minlength = 3,lengthmessage = "姓名长度不能小于3位")
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

}

public class Test {

  public static void main(String[] args) throws NoSuchMethodException, SecurityException, Exception {
		  User user = new User();
		      user.setName("ji");
		  //通过反射解析User类中注解
		  Field[] fields = user.getClass().getDeclaredFields();//拿到类中所有的成员变量 连同私有的也可以获取
		  //循环所有的属性
		  for (Field field : fields) {
	            NotNull notNull = field.getAnnotation(NotNull.class);//获取属性上面 名字为NotNull注解
	            if (notNull != null) {
					//通过属性,生成对应的get方法
	                Method m = user.getClass().getMethod("get" + getMethodName(field.getName()));
					//调用方法  obj就是get方法的返回值
	                Object obj=m.invoke(user);
	                if (obj==null) {
	                    System.err.println(field.getName() +notNull.message());
	                    throw new NullPointerException(notNull.message());
	                }else{
	                	if(String.valueOf(obj).length()<(notNull.minlength())){
	                		 System.err.println(field.getName() +notNull.lengthmessage());
							throw new NullPointerException(notNull.lengthmessage());
	                	}
	                }
	            }
	        }
	   }

		/**
		 * 把一个字符串的第一个字母大写
		 */
	    private static String getMethodName(String fildeName) throws Exception {
	        byte[] items = fildeName.getBytes();
	        items[0] = (byte) ((char) items[0] - 'a' + 'A');
	        return new String(items);
	    }
}

对象克隆

**对象克隆:**从一个已有的对象克隆出来一个新的对象,新对象可以拥有已有对象的数据

克隆时基本数据类型, 直接可以把值克隆到新对象中, 深浅克隆的判断依据主要是关联的其他对象是否被新克隆一个对象.

浅克隆:

克隆一个对象,只把关联对象的地址克隆一下,并没有创建新的关联对象.

public class Person implements  Cloneable{

     int num;
     String name;
     Address address;

    public Person() {
    }

    public Person(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = (Person)super.clone();
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}

public class Address  {

     String  address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }

}
public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {

        Address address = new Address();
                address.setAddress("汉中");

        Person p1 = new  Person(100,"jim");
               p1.setAddress(address);

        Person p2 =p1.clone();
               p2.setName("tom");


               address.setAddress("西安");


        /*
           此次输出的结果就是浅克隆: 因为克隆对象中关联的address对象,没有创建新的对象,只是在克隆时,把address对象的地址克隆过来了
         */
        System.out.println(p1);//Person{num=100, name='jim', address=Address{address='西安'}}
        System.out.println(p2);//Person{num=100, name='tom', address=Address{address='西安'}} 属于浅克隆,Address对象只复制他的地址
    }
}

image-20250320083008667

深克隆

克隆一个对象,把关联的对象也进行克隆,克隆出一个新的关联对象.

如何实现克隆:

public class Person implements  Cloneable{
    
    /*
       重写Object类中clone()方法
    */
    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = (Person)super.clone();//调用父类中的clone方法,克隆对象
        return person;
    }
}


测试
        Person p1 = new Person(100,"jim");
        Person p2 =  p1.clone(); //克隆一个新的对象
        System.out.println(p1==p2);//false

如何实现深克隆

**方式1:**关联的对象也要实现Cloneable接口, 重写clone(),不管有多少级,只要需要深克隆,那么就需要多级克隆.

public class Person implements  Cloneable{

     int num;
     String name;
     Address address;

    public Person() {
    }

    public Person(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = (Person)super.clone();
        person.address = (Address)person.address.clone();   //深度复制  联同person中关联的对象也一同克隆.
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}
public class Address  implements Cloneable{

     String  address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }

    @Override
    protected Address clone() throws CloneNotSupportedException {
        return (Address)super.clone();
    }
}

public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {

        Address address = new Address();
                address.setAddress("汉中");

        Person p1 = new Person(100,"jim");
               p1.setAddress(address);

        Person p2 =p1.clone();
               p2.setName("tom");

               address.setAddress("西安");

        System.out.println(p1);//西安
        System.out.println(p2);//汉中
    }
}

image-20250320082933911

**方式2:**对象序列化,反序列化

​ 对象序列化-- 将对象信息输出

​ 对象反序列化–将输出的对象信息, 重新输入,创建新的对象

public class Person implements Serializable {

     int num;
     String name;
     Address address;

    public Person() {
    }

    public Person(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    /**
     * 自定义克隆方法
     * @return
     */
    public Person myclone() {
            Person person = null;
              try { // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
                      ByteArrayOutputStream baos = new ByteArrayOutputStream();
                      ObjectOutputStream oos = new ObjectOutputStream(baos);
                      oos.writeObject(this);
            // 将流序列化成对象
                    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
                     ObjectInputStream ois = new ObjectInputStream(bais);
                     person = (Person) ois.readObject();
                  } catch (IOException e) {
                     e.printStackTrace();
                  } catch (ClassNotFoundException e) {
                     e.printStackTrace();
                 }
             return person;
          }


    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}

public class Address  implements Serializable {

     String  address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }

}

public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {

        Address address = new Address();
                address.setAddress("汉中");

        Person p1 = new  Person(100,"jim");
        p1.setAddress(address);

        Person p2 =p1.myclone();
               p2.setName("tom");
               address.setAddress("西安");

        System.out.println(p1);//西安
        System.out.println(p2);//汉中


    }
}

image-20250320083118511

设计模式

什么是设计模式

最早的设计模式是建筑领域的,后来发展到软件开发领域.

就是广大的开发前辈们,在实际的开发中把重复出现的问题的解决方案进行优化,最终得到一套最优解决方案(模版).

可以被拿来反复使用.

为什么要学习设计模式

设计模式是好的经验, 学习好的经验

可以提高我们的编程能力和设计能力

可以提高软件设计的标准化,提高开发效率

可以提高代码的复用性,可扩展性

可以更好的理解阅读源码(看懂底层复杂的源码结构)

建模语言

统一建模语言(Unified Modeling Language,UML),是一种软件设计阶段, 用于表达软件设计思路的语言(表达思路的语言)

使用类图的方式, 将类与类之间的关系进行描述

类图: 类和接口关系

类与类的关系

依赖关系

在一个类中的方法中使用到了另一个类,例如把另一个类当做参数传入.(就是一个类用到了另一个类的方法)

具有临时性,关系较弱, 方法执行完后,关系就解除了.

一般也称为: use -a

例如人类中又一个打电话的方法, 在打电话方法中要用到手机类,只是在打电话时,临时使用(手机).

关联关系

在一股类中把另一个类当做自己的成员

例如人类中关联了一个地址类

关联关系可以根据强弱关系分为: 一般关系, 聚合,组合

聚合: 学校和老师关系, 学校不存在了,老师可以独立的存在

面向对象设计原则

单一职责原则

一个类只负责一件事情, 不要让一个类做过多的事情,否则功能耦合度太高,修改一些功能时, 相互会有影响.

尽可能的降低类的粒度.

举例:用户信息类

public class UserInfo {

    private int id;
    private String userName;
    private String gender;
    private String phone;
    private List<Address> addressList;//用户类中关联用户地址

}

public class Address {

    private String province;//地址相关
    private String city;//地址相关
    private String county;//地址相关
    private String detailAddress;//地址相关

}

开闭原则

在程序扩展新功能时, 尽量不要修改原有的代码,尽可能通过扩展新的类来实现功能.

/*
开闭原则案例
 */
class CarDemo{

    public static void main(String[] args) {

      Car bmw  =  new BMWCarFactory().createCar();
      Car aodi  = new AodiCarFactory().createCar();

    }

}

//抽象工厂
abstract class CarFactory{
    abstract  Car createCar();
}

class BMWCarFactory extends CarFactory{

    @Override
    Car createCar() {
        return new BMW("宝马汽车");
    }

}
class AodiCarFactory extends CarFactory{

    @Override
    Car createCar() {
        return new Aodi("奥迪汽车");
    }

}



//抽象汽车
abstract  class Car{
    String name;
}

class BMW extends Car{

    public BMW(String name) {
        this.name = name;
    }
}

class Aodi extends Car{
    public Aodi(String name) {
        this.name = name;
    }
}




依赖倒置原则

上层不应该依赖于细节(实现),上层应该是抽象的, 进行功能的定义即可,变动小 (细节容易变,不稳定)

底层应该依赖于抽象,底层在抽象的指导下进行细节上的具体功能实现(在抽象的规约下,实现具体的功能)

上层应该是抽象, 底层是具体实现,底层依赖于上层的抽象

public class ComputerDemo{

    public static void main(String[] args) {
        IntelCPU intelCPU = new IntelCPU();
        IntelMemory intelMemory = new IntelMemory();

        Computer computer = new Computer(intelCPU, intelMemory);
        computer.startRun();

        AmdCPU amdCpu = new AmdCPU();
        AmdMemory amdMemory = new AmdMemory();

        Computer computer1 = new Computer(amdCpu, amdMemory);
        computer1.startRun();
    }

}

/*
 计算机类
 */
 class Computer {

     private CPU cpu;
     private Memory memory;


    public Computer(CPU cpu, Memory memory) {
        this.cpu = cpu;
        this.memory = memory;
    }

    public void startRun(){
        cpu.calculator();
        memory.storage();
    }
}

//抽象cpu
interface CPU{
     void calculator();
}

interface Memory{
     void storage();
}

//英特尔CPU
class IntelCPU implements CPU{
    @Override
    public void calculator(){
        System.out.println("英特尔处理器运算");
    }
}

//AMDCPU
class AmdCPU implements CPU{
    @Override
    public void calculator() {
        System.out.println("AMD处理器运算");
    }
}

//英特尔内存
class IntelMemory implements Memory{
     @Override
    public void storage(){
        System.out.println("英特尔内存存储");
    }
}

//AMD内存
class AmdMemory implements  Memory{
    @Override
    public void storage() {
        System.out.println("Amd内存存储");
    }
}

接口隔离原则

不要把所有的功能都定义到一个接口中, 应该使用多个接口,把不同的功能定义在不同的接口中

比如: 不会把飞,跑, 游,都定义到一个接口中, 如果一个狗需要跑实现了这个接口, 就要实现飞,跑, 游,功能但是狗不需要飞和游的功能, 造成代码冗余

组合/聚合复用原则

优先使用组合/聚合(关联), 实现代码的复用, 其次才考虑继承.

在类B中,想使用类A中的某些功能,可以使用继承,但是会使得类的体系耦合性高

所以也可以使用关联关系,替代继承关系, 还可以使用更弱的依赖关系实现

   组合/聚合复用原则案例1  使用依赖实现复用
 */
public class A {

    public void method01() {

    }

    public void method02() {

    }
}


class B extends A {


    public void method() {
    }

}

class Test {
    public static void main(String[] args) {
        new B().method01();
        new B().method02();
    }
}
/*
   组合/聚合复用原则案例2  使用组合/聚合实现复用
 */
public class A {

      public void method01(){

      }

      public void method02(){

      }
}


class B{

     A a;

     public void setA(A a){
         this.a = a;
     }

     public void use(){
         a.method01();
         a.method02();
     }

}

class Test{
    public static void main(String[] args) {
         A a = new A();
         B b = new B();
         b.setA(a);
         b.use();
    }
}


/*
   组合/聚合复用原则案例3  使用依赖实现复用
 */
public class A {

      public void method01(){

      }

      public void method02(){

      }
}


class B{


     public void use(A a){//依赖
         a.method01();
         a.method02();
     }


}

里氏替换原则

在使用继承时,如果父类中是非抽象的,那么子类继承父类后,对父类中的非抽象方法进行重写,需要注意小心(谨慎),在使用父类的时候,如果换成子类对象,由于子类对象重写的父类方法, 从而有可能实现不相同,导致结果不对(出错率高)

class Calculator {
        //加法
        public int add(int a,int b){
            return a+b;
        }
}

/*
超级计算器子类
*/
class SuperCalculator extends Calculator{

   //重写了父类加法
    @Override
    public int add(int a, int b) {
        return a+b-5;//只是表示子类继承父类后,重写了父类的方法,对方法进行了修改
    }
}

public class CalculatorDemo{

    public static void main(String[] args) {

        Calculator p = new Calculator();

        int r1 =  p.add(10,5);
        System.out.println("r1="+r1);//15

        Calculator c = new SuperCalculator();
        int r2 =  c.add(10,5);
        System.out.println("r2="+r2);//10
    }

}

实际开发, 父类的功能尽可能定义为抽象

/*
  里氏替换原则演示案例
  计算器父类
*/

abstract  class Calculator {

    //加法  将被子类可能重写的方法定义抽象方法
    public abstract int add(int a,int b);
}

/*
超级计算器子类
*/
class SuperCalculator extends Calculator {

    //重写了父类加法
    @Override
    public int add(int a, int b) {
        return a+b-5;
    }
}

public class CalculatorDemo{

    public static void main(String[] args) {

        Calculator p = new SuperCalculator();
        SuperCalculator c = new SuperCalculator();
        int r1 =  p.add(10,5);
        System.out.println("r1="+r1);

    }

}

迪米特原则

只和朋友交谈,不和陌生人说话,

两个类之间如果没有直接联系,那么就不会相互之间调用,可以通过一个第三方调用

例如:

明星和粉丝,公司之间的交流, 可以通过经纪人来完成

public class DemeterDemo {

    public static void main(String[] args) {
        Star star = new Star("C罗");
        Fans fans = new Fans("李磊");
        Company company = new Company("皇家马德里");

        Agent agent = new Agent("门德斯",star,fans,company);
              agent.meeting();
              agent.business();
    }

}

//经纪人
class Agent{

     String name;
     Star star;
     Fans fans;
     Company company;

    public Agent(String name, Star star, Fans fans, Company company) {
        this.name = name;
        this.star = star;
        this.fans = fans;
        this.company = company;
    }
    //粉丝见面会
    public void meeting(){
         System.out.println("粉丝 "+ fans.name+"与明星 "+ star.name +"见面了");
     }
    //洽谈业务
     public void business(){
         System.out.println(company.name +" 公司 正在与 明星 "+star.name +" 洽谈业务");
     }

}

//明星
class Star{
    String  name;
    public Star(String name) {
        this.name = name;
    }
}

//粉丝
class Fans{
    String  name;
    public Fans(String name) {
        this.name = name;
    }
}

//公司
class Company{
    String  name;
    public Company(String name) {
        this.name = name;
    }
}

面向对象语言设计模式总共有23种

分为3大类:

1.创建型模式

单例模式

​ 单例模式

​ 解决一个类在一个项目中,只能创建一个对象.

单例模式有两种写法:

1.饿汉式(急切式)单例

​ 在类加载时,直接把唯一的对象创建好,调用方法时, 直接返回即可, 不存在线程安全问题.

​ 只是在类加载之初可能用不到,生命周期长.

public class Window {
    /*
       在类加载时, 只创建一个对象
     */
    private static Window window = new Window();

    /*
       构造方法私有化, 在类之外就访问不到构造方法
     */
    private Window() {

    }


    /*
        向外界提供一个方法, 获得new出来的唯一对象
     */
    public static Window getInstance(){
        return window;
    }


    public static  void test(){

    }



}
// 饿汉式
public class test {

    public static void main(String[] args) {

//        new Window();
//        new Window();
//        new Window();

        //在类加载的时候就会创建对象, 对外提供获取对象的方法
        Window.test();

        System.out.println(Window.getInstance());
        System.out.println(Window.getInstance());
        System.out.println(Window.getInstance());
        System.out.println(Window.getInstance());
    }
}

2.懒汉式单例

​ 在类加载时,不着急创建对象,在第一次调用方法时, 才会创建唯一的对象.

​ 这种写法存在安全问题.

public class Window {

    private static Window window = null;

    private Window() {

    }

    public synchronized static Window getInstance() {
        //后面进来的线程拿到的window肯定都不为空,可以多个线程进来拿取对象,并行执行(效率提高了),开头是并发的
        if (window == null){//这个只是为了第一次需要这个对象的时候创建对象


            synchronized (Window.class){

                if (window == null){//只有一个线程进来进行创建对象
                    window = new Window();
                }

            }
        }
        return window;
    }

    /*
        为方法加锁, 但是这种效率低
        window对象创建好后每次线程进入的时候只能一个线程进入效率低
     */
    /*public synchronized static Window getInstance() {
        if (window == null){
            window = new Window();
        }
        return window;
    }
    */

/*

    //此种写法存在线程安全问题
    //如果有两个线程同时进入if代码块就会创建2个对象
    public static Window getInstance() {
        if (window == null){
            window = new Window();
        }
        return window;
    }
*/


    public static void test() {

    }


}
public class Test {

    public static void main(String[] args) {
        Window.test();
        System.out.println(Window.getInstance());
        System.out.println(Window.getInstance());
        System.out.println(Window.getInstance());
    }
}

双重检索+volatile

public class Window {

    /*
   	      volatile修饰的变量, 不同线程中修改了立即可见, 禁止指令的重排序
   	      Window window = new Window();
   	      上面这行代码, 从指令的角度上来讲, 可以有三条指令
	    1.new 申请内存空间
          2. 初始化对象
          3.  把对象地址赋给左边的引用变量  如果正常按这个顺序执行没有问题的.
          但是在执行的过程中, 有可能在执行第2步执行, 同时把第3步提前执行了, 此时对象还可能没有初始化完成
          其他线程可能会拿到一个没有初始化完成的对象(半成品对象)
          所以单例成员需要使用volatile修饰, 禁止指令的重排序
     */
    private volatile static Window window=null;

    private Window(){

    }

    /*
       双重检索,效率提高
     */
    public  static Window getInstance(){

       if(window==null){

           synchronized (Window.class){

               if(window==null){

                   window = new Window();
               }
           }
       }
        return window;
    }

工厂模式

把对象的创建和使用分离, 提供一个工厂类专门负责对象的创建,

一个工程可以创建一类产品

简单工厂

​ 简单工厂并不是设计模式,这只是对工厂模式的引入(只是为了引入工厂模式)

工厂角色 : 全能的工厂 (啥类型的产品都可以生产)

抽象产品(接口/抽象类): 用来组织关系

具体产品: 需要继承/实现抽象产品

​ 客户端---->工厂----->对象

​ 客户端调用工厂方法来获取工厂中的对象,实现对象创建和调用的分离

public interface Car {

      void run();

}

/*
   工厂
 */
public class CarFactory {

     public static Car createCar(String name){
            if(name.equals("aodi")){
                return new Aodi();
            }
            if(name.equals("bmw")){
                return new Bmw();
            }
            if(name.equals("dazhong")){
                return  new DaZhong();
            }
            return null;
     }

}

/*
    具体产品
 */
public class Aodi implements Car{

    @Override
    public void run() {
        System.out.println("奥迪汽车行驶");
    }
}
/*
    具体产品
 */
public class Bmw implements Car{

    @Override
    public void run() {
        System.out.println("宝马汽车行驶");
    }

}

public class DaZhong  implements Car{
    @Override
    public void run() {
        System.out.println("大众汽车行驶");
    }
}

/*
   工厂
 */
public class CarFactory {

     public static Car createCar(String name){
            if(name.equals("aodi")){
                return new Aodi();
            }
            if(name.equals("bmw")){
                return new Bmw();
            }
            if(name.equals("dazhong")){
                return  new DaZhong();
            }
            return null;
     }

}
public class Test {




    public static void main(String[] args) {

        //Aodi aodi1 = new Aodi();  自己new对象

        Car bmw  =  CarFactory.createCar("bmw");
        Car aodi  = CarFactory.createCar("aodi");

          bmw.run();
          aodi.run();
    }
}

工厂方法

首先将工厂也进行抽象, 一个抽象工负责一类产品, 定义工厂规则.

为每一种具体的产品都提供一个专门的工厂生产.

这样后来添加新产品时, 不需要修改原来的工厂类, 直接扩展一个新的工厂即可.

遵守了开闭原则

工厂方法中,一个工厂只负责一类产品生产,但是产品多了以后, 会增加代码量(弊端)

```java
public interface Car {

      void run();

}

```
public interface CarFactory {

       Car createCar();
}

public class Aodi implements Car {

    @Override
    public void run() {
        System.out.println("奥迪汽车行驶");
    }
}
public class AodiFactory implements CarFactory {

    @Override
    public Car createCar() {
        return new Aodi();
    }
    
}

public class Bc implements  Car{
    @Override
    public void run() {
        System.out.println("奔驰汽车形式");
    }
}

public class BCFactory  implements CarFactory{
    @Override
    public Car createCar() {
        return new Bc();
    }
}

public class Test {

    public static void main(String[] args) {

           CarFactory aodicarFactory = new AodiFactory();
           Car aodi =  aodicarFactory.createCar();
           aodi.run();

           CarFactory bmwcarFactory = new BmwFactory();
           Car bmw = bmwcarFactory.createCar();
           bmw.run();

           Car car = new BCFactory().createCar();
               car.run();


    }
}

抽象工厂

​ 抽象工厂模式中, 工厂不再只负责单一产品的生产,

而是工厂可以生产同一家公司(家族),在一个工厂中可以生产同一家(家族)的多个产品(例如: 小米家族手机, 小米家族汽车),这样就不需要太过冗余的工厂类

image-20250321200454152

public interface Car {

        void run();
}

public interface Phone {

       void  call();

}

public interface AbstractFactory {

       Car getCar();
       Phone getPhone();



}
public class AodiCar implements Car{

    @Override
    public void run() {
        System.out.println("奥迪汽车行驶");
    }

}

public class AodiPhone implements Phone {
    @Override
    public void call() {
        System.out.println("奥迪手机打电话");
    }
}

public class AodiFactory implements AbstractFactory {
    @Override
    public Car getCar() {
        return new AodiCar();
    }

    @Override
    public Phone getPhone() {
        return new  AodiPhone();
    }
}

public class BmwCar implements Car{

    @Override
    public void run() {
        System.out.println("宝马汽车行驶");
    }

}
public class BmwPhone implements Phone {

    @Override
    public void call() {
        System.out.println("宝马手机打电话");
    }

}

public class BmwFactory implements AbstractFactory {
    @Override
    public Car getCar() {
        return new BmwCar();
    }

    @Override
    public Phone getPhone() {
        return new BmwPhone();
    }




}

public class Test {

    public static void main(String[] args) {
        AbstractFactory aodiFactory = new AodiFactory();
        Car aodiCar = aodiFactory.getCar();
        Phone aodiphone = aodiFactory.getPhone();
              aodiCar.run();
              aodiphone.call();

        AbstractFactory bmwFactory = new BmwFactory();
        Car bmwCar = bmwFactory.getCar();
        Phone bmwPhone = bmwFactory.getPhone();
              bmwCar.run();
              bmwPhone.call();
    }
}

原型模式

如果我们需要创建多个对象时,每次new+构造方法执行速度慢(原因:每次都要执行构造方法中的逻辑(耗费时间))

那么我们就可以先闯几年一个对象,在已有对象的基础上进行对象克隆(拷贝),提高创建对象的效率

例如: 要手写5份简历, 太浪费时间了

​ 写好一份后复印4次, 就可以得到多个对象, 效率高.

对象克隆

​ 如何实现对象克隆:

​ 1.类实现Cloneable接口 重写Object类中的clone()

​ 2.序列化, 反序列化

注意深克隆和浅克隆

2.结构型模式

代理模式

​ 案例: 汽车厂只管造汽车, 不直接把汽车卖给个人客户.

​ 把卖汽车交给代理商(4S店)卖给普通个人客户

​ 代理商就可以在中间向客户介绍汽车信息, 卖完汽车后, 还可以帮助客户办理手续

​ 代理商在中间增加了一些额外的功能(方法增强).

汽车厂自己卖车, 汽车厂不仅要卖车,还要介绍汽车, 还要帮助办理手续,都要自己完成, 压力大
    sell(){
    介绍汽车
    汽车厂卖车
    办理手续
}


sell(){
    汽车厂卖车
}

//代理
sell(){
    介绍汽车
     sell();
    办理手续
}

代理模式: 为目标对象(汽车厂)提供一个代理对象,不让目标对象之间与客户进行交互.

而是通过代理对象与客户间隔交互

3.行为模式

好处: 代理对象可以为目标对象提供保护

​ 代理对象可以为目标对象扩展功能

​ 代理对象可以降低目标对象和客户之间的耦合度

(汽车厂和客户没有粘连)(转心干一件事,干多个事,不能精通)

代码结构

抽象主题(接口/抽象类): 汽车厂和代理做同一件事, 所以进行抽象, 都是卖汽车

真实主题(目标对象/汽车厂)

代理对象

代理模式又分为静态代理和动态代理

静态代理:

​ 静态代理在一些简单的场景下可以使用,

​ 因为一个代理类, 只能为那些实现了某个接口的目标类实现代理(跟代理类的接口一样),

​ 如果要为其他接口的目标类实现代理,就必须重新创建新的代理类

​ 在复杂场景下不太合适了

(静态代理只能代理跟代理类实现一样接口的实现类(目标类) ,如果要代理其他的接口的实现类, 那必须重新创建一个代理类,跟这个类实现了同一个接口)

/*
   抽象操作定义 卖东西
 */
public interface Sell {

       void sell();

}

public class CarFactoryImpl implements Sell {

    @Override
    public void sell() {
        //System.out.println("介绍汽车");
        System.out.println("汽车厂卖汽车"); //汽车厂真实的只是卖汽车这个动作.
        //System.out.println("办理手续");
    }

}

public class PhoneFactory  implements Sell{
    @Override
    public void sell() {
        System.out.println("手机厂卖手机");
    }
}

/*
  静态代理,实际中很少使用静态代理,因为其代理类实现的接口必须与目标类实现接口一致,扩展起来就比较麻烦
 */
public class StaticProxy  implements Sell{

    Sell sell;//接收真实主题(目标对象)

    Create create;

    public StaticProxy(Sell sell) {
        this.sell = sell;//接收一个真实主题
    }

    public StaticProxy(Create create){
        this.create = create;
    }

    @Override
    public void sell() {
        System.out.println("产品介绍");
       try {
           sell.sell();//真实主题
       }catch (Exception e){
           System.out.println("");
       }
        System.out.println("办理手续");
    }


}

public class Test {

    public static void main(String[] args) {

       // CarFactoryImpl carFactory1 = new CarFactoryImpl();
                     ///  carFactory1.sell();


        Sell carFactory = new CarFactoryImpl();//真实主题
        //创建汽车厂代理对象
         StaticProxy staticProxy = new StaticProxy(carFactory);
                     staticProxy.sell();//客户看似调用的是代理方法


        PhoneFactory phoneFactory = new PhoneFactory();
        StaticProxy staticProxy1 = new StaticProxy(phoneFactory);
        staticProxy1.sell();

    }
}

动态代理

动态代理可以在运行时,根据不同的类生成代理对象,可以为所有的任意类提供代理

动态代理分为:

jdk代理

jdk代理是通过反射机制实现的, 在运行时,可以动态的获得目标类的接口,获得接口中的方法信息,从而为目标类生成代理对象

只要写一个代理对象生成器, 就可以为所有的类生成代理对象,

但是jdk代理方式实现时, 目标类必须要实现一个接口, 不实现接口,就不能使用jdk代理

  return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
/*
   抽象操作定义 卖东西
 */
public interface SellCar {

      void sell();


}
/*
    汽车厂
 */
public class CarFactoryImpl implements SellCar {

    @Override
    public void sell() {
        System.out.println("汽车厂卖汽车");
    }

}

public class Test {

    public static void main(String[] args) {

          CarFactoryImpl carFactory = new CarFactoryImpl();//创建真实主题
          DynamicProxy dtproxy =  new DynamicProxy(carFactory);//创建代理对象生成器
          //这才是真正的创建动态代理对象   获取目标类所实现的接口
          SellCar carfactory =    (SellCar)dtproxy.getProxy();
          carfactory.sell();//使用代理对象调用接口中的方法,获取当前调用的方法,最终调用invoke方法
    }
}
cglib代理

​ cglib代理师spring中的一个实现, 使用cglib代理,目标类可以不用实现接口

采用底层的字节码生成技术,为我们的目标类生成子类对象, 采用方法拦截技术,在调用方法时, 会进入到拦截中, 获得所调用的父类方法即可

目标类不能是final修饰的, 目标类中的方法如果为final, static修饰 就不能进行增强

//具体主题
public  class CarFactoryImpl {

	 
	    public  void sell() {
	        System.out.println("汽车厂卖汽车");
	    }

}
/*
 * 动态代理生成器类
 */
public class CGLibProxy implements MethodInterceptor {
    
	    private Enhancer enhancer = new Enhancer();
	    
	    public Object getProxy(Class<?> clazz){  
	        enhancer.setSuperclass(clazz);  
	        enhancer.setCallback(this);  
	        return enhancer.create();  
	    }  
	    /*
	     * 拦截所有目标类方法的调用 
	     * 参数: 
	     * obj  目标实例对象 
	     * method 目标方法的反射对象 
	     * args 方法的参数 
	     * proxy 代理类的实例 
	     */
	    public Object intercept(Object obj, Method method, Object[] args,  
	            MethodProxy proxy) throws Throwable {
	        //代理类调用父类的方法  
	        System.out.println("开始事务");  
	        Object obj1 = proxy.invokeSuper(obj, args);  
	        System.out.println("关闭事务");  
	        return obj1;  
	    }
}
public class Test {

	 public static void main(String[] args) {
		  CGLibProxy proxy = new CGLibProxy();
		  CarFactoryImpl carFactory = (CarFactoryImpl) proxy.getProxy(CarFactoryImpl.class);
		  carFactory.sell();
	}
}

spring中两种代理方式都进行了实现, 可以根据不同的情况进行自动选择

1.单例对象, 没有实现接口的类,可以使用cglib代理

2.原型对象(创建多个对象) ,实现接口的类,可以使用jdk代理

3.行为模式

模版方法模式

模版方法模式:

​ 将程序中一些固定流程的步骤进行提取(公共步骤进行抽取)(银行取款, 存款, 转账,抽号, 排队, 操作,评分),

在抽象父类中提供一个模版方法(固定流程的步骤),在模版方法中,按顺序把固定步骤(固定流程(就是模版))的方法进行调用(执行)

其中有一些方法时公共的都一样,在父类中进行实现即可,

其中还有一些方法实现不同, 定义为抽象的, 就需要创建不同的子类来继承重写(进行不同的实现),

使用时,子类对象只要调用模版方法, 相同的功能调用抽象父类中的方法,不同的调用子类中重写的方法.

符合开闭原则,增加功能时,只需要扩展新的类即可

public abstract class AbstractBank {

       //办理业务方法 -- 模板方法
       public void handle(){
               this.offerNumber();//抽号

               this.lineup();//排队

               this.business();//具体的操作

               this.score();//平分
       }

       //抽号
       public void offerNumber(){
           System.out.println("抽号");
       }
      //排队
      public void lineup(){
          System.out.println("排队");
      }

      //办理具体业务--抽象方法,由具体子类实现
      public abstract void business();

      //评分
      public void score(){
          System.out.println("评分");
      }

      //其他

}

/*
   存钱业务
 */
public class StoreBusiness extends AbstractBank {

    //办理的具体业务
    public void business() {
        System.out.println("我要存钱");
    }

}
/*
  转账业务类
 */
public class TransferBusiness  extends AbstractBank{

    //转账
    public void business() {
        System.out.println("我要转账");
    }

}

public class Test {


    public static void main(String[] args) {

        StoreBusiness storeBusiness = new StoreBusiness();
        storeBusiness.handle();

        System.out.println("===================================");

        TransferBusiness transferBusiness = new TransferBusiness();
        transferBusiness.handle();
    }
}

策略模式

可以将条件选择策略的实现,转为策略对象,传入哪个策略就使用哪个策略

不同的情况封装到不同的类里面,使用哪个就传入哪个策略,避免写大量的不优雅的if -else条件判断

不同的策略不同的对象,

public interface Strategy {//抽象策略类

    void show();

}

/*
  为春节准备的促销活动A
 */
public class StrategyA implements Strategy {//具体策略类

    public void show() {
        System.out.println("春节活动: 买一送一");
    }

}

/*
  为中秋准备的促销活动B
 */
public class StrategyB implements Strategy {//具体策略类


    public void show() {
        System.out.println("中秋活动: 满200元减50元");
    }
    
}
/*
  为国庆准备的促销活动C
 */
public class StrategyC implements Strategy {//具体策略类


    public void show() {
        System.out.println("国庆活动:满1000元加一元换购任意200元以下商品");
    }
    
}
public class Test {

    public static void main(String[] args) {
       /*
        if(a==1){
              if(){
                  if(){
                  }
              }
        }
        if(a==2){
                  if(){
                      if(){
                      }
              }
        }

        if(a==3){

        }*/

        SalesMan salesManA = new SalesMan(new StrategyA());
        salesManA.salesManShow();

        SalesMan salesManB = new SalesMan(new StrategyB());
        salesManB.salesManShow();

        SalesMan salesManC = new SalesMan(new StrategyC());
        salesManC.salesManShow();

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值