初入设计模式

设计模式-创建型模式

1.单例模式

懒汉式

  1. 类加载顺序

    1. 开辟空间

    2. 初始化空间

    3. 赋值对象

    4. Demo demo = new Demo();
      
  2. 可能因为编译器,JIT,CPU的原因,上面的顺序坑能会被打乱,导致指令重排(执行结果不会被改变),那要怎么解决呢?

  3. 在变量上添加关键字volatile

    1. private volatile static LazyDemo lazyDemo; 
      
    2. volatile修饰的变量不会被指令重排

饿汉式

  1. 直接上代码

  2. public class HungryType {
        private static final HungryType MY_UTIL = new HungryType();
    
        private HungryType(){}
    
        public static HungryType getInstance(){
            return MY_UTIL;
        }
    }
    

工厂模式

工厂方法

创建型方式, 省去了new 的过程

  1. 定义抽象产品

    1. 抽象产品方法

    2. abstract class Car{
          abstract void run ();
      }
      
      
  2. 充当具体的产品角色

  3. /**
     * 角色1
     */
    class Bmw extends Car {
    
        @Override
        void run() {
            System.out.println("我是BMW");
        }
    }
    
    /**
     * 角色2
     */
    class BenChi extends Car{
    
        @Override
        void run(){
            System.out.println("我是奔驰");
        }
    }
    
  4. 定义抽象工厂

    1. /**
       * 抽象工厂
       */
      abstract class CarFactory{
          abstract Car productCar();
      
          public void run(){
              productCar().run();
          }
      }
      
      
  5. 定义工厂角色

    1. /**
       * BenChi工厂角色
       */
      class BenChiFactoryItem extends CarFactory{
          @Override
          Car productCar() {
              return new BenChi();
          }
      }
      /**
       * Bmw工厂角色
       */
      class BmwFactoryItem extends CarFactory{
          @Override
          Car productCar() {
              return new Bmw();
          }
      }
      
  6. 运行测试

    1. public static void main(String[] args) {
          //运行奔驰
          CarFactory benChiFactoryItem = new BenChiFactoryItem();
          benChiFactoryItem.run();
      
          //运行宝马
          CarFactory bmwFactoryItem = new BmwFactoryItem();
          bmwFactoryItem.run();
      
      }
      
  7. 由此得出工厂方法所需的几个角色

    1. 抽象产品角色
    2. 具体的产品角色
    3. 抽象工厂角色
    4. 具体的抽象工厂角色
  8. 缺点

    1. 添加新产品会增加具体工厂类和具体产品类,这无疑会增加系统的复杂度,带来更多的开销
  9. 优点

    1. 所有的具体工厂类都具有同一抽象父类
    2. 所有的具体抽象角色都有共同的抽象父类,比如这里的CarFactory就是BmwFactoryItemBenChiFactoryItem的父类,具体细节完全分装在具体抽象角色中.
    3. 如果加入新的产品角色,只需要添加一个具体工厂和一个具体产品,无需修改之前代码,符合开闭原则

建造者模式

  1. 创建抽象得到建造者

    1. abstract class Build {
          public abstract Build buildA(String msg);
      
          public abstract Build buildB(String msg);
      
          public abstract Build buildC(String msg);
      
          public abstract Build buildD(String msg);
      
          public abstract Product getProduct();
      }
      
    2. 抽象出要建造什么产品

    3. 由工人来实现这些产品的创建顺序以及内容

  2. 创建产品

    1. class Product{
          private String buildA = "汉堡";
          private String buildB = "可乐";
          private String buildC = "竖条";
      
          @Override
          public String toString() {
              return "Product{" +
                      "buildA='" + buildA + '\'' +
                      ", buildB='" + buildB + '\'' +
                      ", buildC='" + buildC + '\'' +
                      ", buildD='" + buildD + '\'' +
                      '}';
          }
      
          public String getBuildA() {
              return buildA;
          }
      
          public void setBuildA(String buildA) {
              this.buildA = buildA;
          }
      
          public String getBuildB() {
              return buildB;
          }
      
          public void setBuildB(String buildB) {
              this.buildB = buildB;
          }
      
          public String getBuildC() {
              return buildC;
          }
      
          public void setBuildC(String buildC) {
              this.buildC = buildC;
          }
      
          public String getBuildD() {
              return buildD;
          }
      
          public void setBuildD(String buildD) {
              this.buildD = buildD;
          }
      
          private String buildD = "甜点";
      }
      
    2. 这里的产品可以有默认值, 当调用是传入值的时候就会使用传入的内容,调用时没有传值就会使用默认值

  3. 创建工人 worker

    1. class Worker extends Build{
      
          private final Product product;
          public Worker(){
              product = new Product();
          }
      
          @Override
          public Build buildA(String msg) {
              product.setBuildA(msg);
              return this;
          }
      
          @Override
          public Build buildB(String msg) {
              product.setBuildA(msg);
              return this;
          }
      
          @Override
          public Build buildC(String msg) {
              product.setBuildA(msg);
              return this;
          }
      
          @Override
          public Build buildD(String msg) {
              product.setBuildA(msg);
              return this;
          }
      
          @Override
          public Product getProduct() {
              return product;
          }
      }
      
    2. 工人来决定创建顺序以及内容

    3. 因为每个build方法返回的都是this,所以当调用的时候可以实现链式调用

  4. 测试

    1. public static void main(String[] args) {
          Worker woker = new Worker();
          //直接调用有默认值
          //Product product = woker.getProduct();
          Product product = woker.buildA("a").buildB("b").buildC("C").buildD("D").getProduct();
          System.out.println("product = " + product);
      }
      
    2. 由于工人(Worker)里面的实现方法返回的this,所以这里可以实现链式调用

  5. 角色

    1. 建造者 Build
    2. 产品 Product
    3. 工人 Worker
  6. 缺点

    1. 如果产品之间差异性过大,不适用建造者模式,因此使用范围受到限制。
    2. 如果内部变化复杂,则需要很多建造者实现这种变化,导致系统变得很庞大。
  7. 优点

    1. 产品的建造和表示分离实现了解耦。
    2. 建造者模式可以使客户端不必知道内部组成的细节。
    3. 将复杂的产品的创建步骤分解在不同的方法中,是创建过程更清晰。
    4. 具体的建造者之间相互独立,有利于扩展,增加新的建造者无需修改原有的类库,符合开闭原则
  8. 使用场景

    1. 产品对象有共同的特性
    2. 隔离对象创建和使用,并使得相同的创建过程创建不同的场景

原型模式

  1. 原型模式本质上就是对象克隆

  2. 基本使用

    1. public class Dept implements Cloneable{
      
      
          private String name;
          private Date date;
      
          @Override
          protected Object clone() throws CloneNotSupportedException {
              return super.clone();
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public Date getDate() {
              return date;
          }
      
          @Override
          public String toString() {
              return "Dept{" +
                  "name='" + name + '\'' +
                  ", date=" + date +
                  '}';
          }
      
          public void setDate(Date date) {
              this.date = date;
          }
      }
      
      
    2. Date date = new Date();
      
      Dept dept = new Dept();
      dept.setDate(date);
      dept.setName("zhangsan");
      System.out.println("dept = " + dept);
      System.out.println("dept = " + dept.hashCode());
      
      Dept clone = (Dept) dept.clone();
      System.out.println("clone = " + clone);
      System.out.println("clone = " + clone.hashCode());
      
    3. 这样可以实现克隆,但是两个Dept应用的是同一个Date,如果Date被改变,那么原有的Dept和克隆的Dept都会被改变. 只是实现了浅克隆

    4. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l6dU1ZZz-1657594095892)(C:\Users\mucd\AppData\Roaming\Typora\typora-user-images\1657442494931.png)]

  3. 修改Deptclone方法,实现对象深克隆

    1. public class Dept implements Cloneable {
      
      
          private String name;
          private Date date;
      
          @Override
          protected Object clone() throws CloneNotSupportedException {
      
              Object obj = super.clone();
              Dept dept = (Dept) obj;
              date = (Date) date.clone();
      
              return dept;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public Date getDate() {
              return date;
          }
      
          @Override
          public String toString() {
              return "Dept{" +
                      "name='" + name + '\'' +
                      ", date=" + date +
                      '}';
          }
      
          public void setDate(Date date) {
              this.date = date;
          }
      }
      
      
    2.     public static void main(String[] args) throws CloneNotSupportedException {
              Date date = new Date();
      
              Dept dept = new Dept();
              dept.setDate(date);
              dept.setName("zhangsan");
              System.out.println("dept = " + dept);
              System.out.println("dept = " + dept.hashCode());
              //修改时间
              date.setTime(220020);
              //克隆出来的对象不会被改变
              Dept clone = (Dept) dept.clone();
              System.out.println("clone = " + clone);
              System.out.println("clone = " + clone.hashCode());
      
          }
      
    3. Dept的clone方法是重点

代理模式

  1. 角色

    1. 抽象角色
    2. 真实角色,被代理的
    3. 代理角色,代理真实角色,有一些附属操作
    4. 客户,访问代理角色
  2. 实现

    1. 抽象角色

      1. pubic interface Animal{
            void eat();
        
            void call();
        }
        
    2. 真实角色,被代理的角色

      1. public class Cat implements Animal{
            @Override
            public void eat() {
                System.out.println("cat eat ...");
            }
        
            @Override
            public void call() {
                System.out.println("cat call ...");
            }
        }
        
        
      2. 被代理的都是原有的功能

    3. 代理角色,代理类,代理真实角色,通常具有附属操作

      1. public class AnimalProxy implements Animal{
            private Animal animal;
            public void setAnimal(Animal animal) {
                this.animal = animal;
            }
        
            @Override
            public void eat() {
                newMethod("大吃");
                animal.eat();
            }
        
            @Override
            public void call() {
                newMethod("大叫");
                animl.call();
            }
            // 附属操作
            public void  newMethod(String msg){
                System.out.println("Debug:"+new Date()+" "+msg);
            }
        }
        
        
    4. 测试

      1. public class Main02 {
            public static void main(String[] args) {
                Cat cat = new Cat();
                AnimalProxy animalProxy = new AnimalProxy();
                animalProxy.setAnimal(cat);
        
                animalProxy.call();
                animalProxy.eat();
            }
        }
        
      2. 运行的是代理类, 把被代理的Catset进了CatProxy

    5. 扩展

      1. 如果此时我想添加一个Dog类,那么实现方式如下

      2. 首先创建一个被代理的Dog类,同样实现Animal

      3. public class Dog implements Animal{
            @Override
            public void eat() {
                System.out.println("dog eat ...");
            }
        
            @Override
            public void call() {
                System.out.println("dog call ...");
            }
        }
        
        
      4. AnimalProxy代理类不用改动

      5. 运行测试

      6. public static void main(String[] args) {
            Cat cat = new Cat();
            AnimalProxy animalProxy = new AnimalProxy();
            animalProxy.setAnimal(cat);
            animalProxy.call();
            animalProxy.eat();
        
            Dog dog = new Dog();;
            animalProxy.setAnimal(dog);
            animalProxy.call();
            animalProxy.eat();
        }
        

动态代理

  1. 动态代理角色和静态代理相同

  2. 党台代理雷士动态生成的

  3. 实现动态代理的几种分类

    1. 基于接口
      1. JDK
    2. 基于类
      1. cglib
    3. java字节码
      1. java ssist
  4. 实现

    1. 抽象角色

      1. public interface UserService {
        
            void add();
            void delete();
            void update();
        
        }
        
    2. 真实角色

      1. public class UserServiceImpl implements UserService{
            @Override
            public void add() {
                System.out.println("add ....");
            }
        
            @Override
            public void delete() {
                System.out.println("delete ....");
        
            }
        
            @Override
            public void update() {
                System.out.println("update ....");
        
            }
        }
        
        
    3. 代理角色,代理工具类

      1. public class UserProxyHandler implements InvocationHandler {
            /**
             * 传入谁就代理谁
             */
            private Object target;
            public void setTarget(Object target) {
                this.target = target;
            }
        
        
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //代理方法执行之前要执行内容
                log(method.getName());
                //使用反射执行target中的方法,args是方法的参数
                Object invoke = method.invoke(target, args);
        
                return invoke;
            }
        
            /**
             * 获取到被代理类
             * @return 被代理对象
             */
            public Object getProxyHandler(){
                return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
            }
        
            /**
             * 横切方法
             * @param msg
             */
            public void log(String msg) {
                System.out.println(new Date()+","+msg);
            }
        
        }
        
    4. 运行测试

      1. public static void main(String[] args) {
            //被代理角色
            UserServiceImpl userService = new UserServiceImpl();
            UserProxyHandler userProxyHandler = new UserProxyHandler();
            userProxyHandler.setTarget(userService);
        
            UserService proxyHandler1 = (UserService) userProxyHandler.getProxyHandler();
            proxyHandler1.delete();
        
        }
        
    5. 结论

      1. 在第4步的代理工具类中可以看到, setTarget方法传入什么对象,那么就会自动的代理什么对象,那么就不需要一个角色一个代理,大大减少代码量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值