0
点赞
收藏
分享

微信扫一扫

设计模式(12):代理模式

后来的六六 04-02 21:00 阅读 2

文章目录

开闭原则

例子

img

img

其中AbstractSkin是抽象类,皮肤类:

package com.linghu.demo01;

/**
 * 抽象皮肤类
 * @author linghu
 * @date 2024/2/1 15:42
 */
public abstract class AbstractSkin {
    //展示皮肤的方法
    public abstract void display();
}

另外的DefaultSpecificSkinHeimaSpecificSkinSouGouInput三个是子类,不动这三个子类的情况下,自己新建皮肤类,然后在下面代码【2】处进行更改,实现良好的扩展性。

Test类如下:

package com.linghu.demo01;

/**
 * @author linghu
 * @date 2024/2/1 15:58
 */
public class Client {
    public static void main(String[] args) {
        //1、创建搜狗输入法对象
        SouGouInput input = new SouGouInput();
        //2、创建皮肤对象
        HeimaSpecificSkin skin = new HeimaSpecificSkin();
//        DefaultSpecificSkin skin = new DefaultSpecificSkin();
        //3、将皮肤设置到输入法中
        input.setSkin(skin);
        //4、显示皮肤
        input.display();
    }
}

img

总结

对扩展开放,对修改关闭的含义就是: 我们可以在定义扩展其他皮肤类【2】,只要在上述代码中新建对象即可。不需要修改原有的DefaultSpecificSkinHeimaSpecificSkinSouGouInput三个子类。

里氏代换原则

基本介绍

例子

为遵循里氏替换原则的后果:

package com.weirdo.principle.liskov;
public class Liskov {
    public static void main(String[] args) {
        A a = new A();
        System.out.println("11-3="+a.func1(11,3));
        System.err.println("==========================");
        B b = new B();
        //这里本意求11-3
        System.out.println("11-3="+b.func1(11,3));
        System.out.println("1-8="+b.func1(1,8));
        System.out.println("11+3+1="+b.func2(11,3));
    }
}
//A类
class A {
    //返回两个数的差
    public int func1(int num1, int num2) {
        return num1 - num2;
    }
}
//B类继承了A
//增加了一个新功能:完成两个数相加,然后和1求和
class B extends A {
    //这里,重写了A类的方法,可能是无意识
    public int func1(int a, int b) {
        return a + b;
    }
    public int func2(int a, int b) {
        return a + b + 1;
    }
}

img

依赖倒转原则

基本介绍

例子

如下图所示,扩充的IntelCpu类没法更换成其他的CPU类,就很不方便

img

在这个Computer类中,如果我们要添加一个CPU的话,就要修改Computer类,这就会导致臃肿麻烦。违背了开闭原则!

img

接下来使用依赖倒转原则,就是把类抽取出接口:

img

如上做的好处就是,如果有其他品牌的CPU加入,我们只需要在实现类旁边进行扩充,去实现接口即可!

接口隔离原则

基本介绍

例子

image-20240204084852365

image-20240204085145523

image-20240204093752134

上面的代码设计如下图:

image-20240204093817395

这种设计的缺陷在于,黑马品牌的安全门具有防盗,防水,防火的功能。现在如果我们还需要再创建一个传智品牌的安全门,而该安全门只具有防盗、防水功能呢?很显然如果实现SafetyDoor接口就违背了接口隔离原则,那么我们如何进行修改呢?看如下类图:

image-20240204093905573

改进以后的代码:

package com.linghu.demo04.after;

/**
 * 新品牌门的加入
 * @author linghu
 * @date 2024/2/4 9:57
 */
public class NewDoor implements AntiTheft,Fireproof{
    @Override
    public void antiTheft() {
        System.out.println("防盗");
    }

    @Override
    public void fireproof() {
        System.out.println("防火");
    }
}

新品牌的门的加入就不会在影响之前的门的牌子类了。这就是接口隔离的好处。

image-20240204102723838

迪米特法则

基本介绍

image-20240204103620060

为什么要找软件公司呢?这个外包公司可以帮助程序员和客户省去交流的成本,沟通的成本,提高效率!

例子

image-20240204111836954

package com.linghu.demo05;

/**
 * @author linghu
 * @date 2024/2/4 11:12
 */
public class Client {
    public static void main(String[] args) {
        //创建经纪人类
        Agent agent = new Agent();
        //创建明星类
        Star star = new Star("李小龙");
        agent.setStar(star);
        //创建粉丝类
        Fans fans = new Fans("令狐");
        agent.setFans(fans);
        //创建公司对象
        Company company = new Company("好莱坞");
        agent.setCompany(company);
        //开会和洽谈业务~
        agent.meeting();
        agent.business();
    }
}

image-20240204111927619

合成复用原则

基本介绍

例子

image-20240204140653772

image-20240204140710419

创建者模式

基本介绍

创建型模式分为:

  • 单例模式
  • 工厂方法模式
  • 抽象工程模式
  • 原型模式
  • 建造者模式

单例设计模式

饿汉式-方法1:静态变量
package com.linghu.demo06.pattern;

/**
 * 饿汉式
 * 静态变量-创建类对象
 * @author linghu
 * @date 2024/2/4 14:41
 */
public class Singleton {
    //1、私有化构造器,防止外部创建该类对象,只能让外部通过get方法访问本类
    private Singleton(){

    }
    //2、在成员位置创建该类对象
    private static Singleton instance=new Singleton();
    //3、对外提供静态方法获取该类对象
    public static Singleton getInstance(){
        return instance;
    }
}

image-20240204145031036

饿汉式-方法2:静态代码块

这个方法跟上面的方法其实差不多。

package com.linghu.demo06.pattern;

/**
 * 饿汉式
 * 静态变量-创建类对象
 * @author linghu
 * @date 2024/2/4 14:41
 */
public class Singleton {
    //1、私有化构造器,防止外部创建该类对象,只能让外部通过get方法访问本类
    private Singleton(){

    }
    //2、在成员位置创建该类对象
    private static Singleton instance;//null
    static {
       instance=new Singleton();   
    }
    //3、对外提供静态方法获取该类对象
    public static Singleton getInstance(){
        return instance;
    }
}

总结
懒汉式-方式1(线程不安全)

这个方式就是用饿汉式的第一种方式进行调整就可以了:

public class Singleton {
    //1、私有化构造器,防止外部创建该类对象,只能让外部通过get方法访问本类
    private Singleton(){

    }
    //2、在成员位置创建该类对象
    private static Singleton instance;
    //3、对外提供静态方法获取该类对象
    public static Singleton getInstance(){
        //instance=new Singleton();//在这里做了调整,使用该对象的时候再调用,就不会浪费了
        if (instance==null){
            instance=new Singleton();
        }
        return instance;
    }
}

如上的代码中,我们加入了一个if判断,这里的操作叫做 懒加载!

懒汉式-方式2(线程安全)

在上面懒加载的情况下加入一个 synchronized同步锁就可以了:

package com.linghu.demo06.pattern01;

/**
 * @author linghu
 * @date 2024/2/4 17:01
 */
public class Singleton {
    //1、构造器私有化
    private Singleton(){

    }
    //2、创建类对象
    private static Singleton instance;

    //3、对外提供静态方法获取该对象
    public static synchronized Singleton getInstance(){
        if (instance==null){//当线程1进入以后,先判断,线程2在方法外面等待
            //等待到线程1对象创建或者返回完毕释放锁以后,线程2才开始进入
            instance=new Singleton();
        }
        return instance;
    }
}

懒汉式-方式3(双重检查锁)
package com.linghu.demo07;

/**
 * 双重检查方式
 * @author linghu
 * @date 2024/2/5 10:33
 */
public class Singleton {
    //1、私有构造器
    private Singleton(){}

    private static Singleton instance;

    //对外提供静态方法获取该对象
    public static Singleton getInstance(){
        //第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实例
        if (instance==null){
            synchronized (Singleton.class){
                //第二次判断,抢到锁以后是否为null
                if (instance==null){
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }
}

image-20240205104627478

懒汉式-方式4(静态内部类)
package com.linghu.demo08;

/**
 * @author linghu
 * @date 2024/2/5 11:21
 */
public class Singleton {
    //1、私有化构造器
    private Singleton(){}
    //2、静态内部类提供实例
    private static class SingletonHolder{//这个类只能内部用,外界访问不了
        //调用getInstance方法的时候才能初始化INSTANCE,而且只会被调用一次
        private static final Singleton INSTANCE=new Singleton();
    }
    //3、对外提供静态方法获取该对象
    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

第一次加载Singleton类时不会去初始化INSTANCE,只有第一次调用getInstance,虚拟机加载SingletonHolder并初始化INSTANCE,这样不仅能确保线程安全,也能保证 Singleton 类的唯一性。

枚举方式-饿汉式(不考虑内存空间)
package com.linghu.demo09;

/**
 * 枚举方式
 * @author linghu
 * @date 2024/2/5 11:34
 */
public enum Singleton {
    INSTANCE;
}

image-20240205113613883

JDK源码解析-RunTime类的单例设计模式

image-20240205143503998

如上可以看出代码中提供了私有化构造器、静态访问对象的方法、静态变量对象:

public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class <code>Runtime</code> are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the <code>Runtime</code> object associated with the current
     *          Java application.
     */
    public static Runtime getRuntime() {
        return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {}

工厂模式

引入工厂模式的目的是为了:解耦!

三种工厂:

  • 简单工厂模式(不属于GOF的23种经典设计模式)
  • 工厂方法模式
  • 抽象工厂模式
引例

image-20240205161931148

image-20240205164717080

package com.linghu.demo10;

/**
 * @author linghu
 * @date 2024/2/5 16:20
 */
public abstract class Coffee {
    //获取咖啡的名字,定义成抽象方法
    public abstract String getName();
    public void addMilk(){
        System.out.println("加奶~");
    }
    public void addSugar(){
        System.out.println("加糖~");
    }
}

package com.linghu.demo10;

/**
 * @author linghu
 * @date 2024/2/5 16:31
 */
public class CoffeeStore {

    //根据不同的咖啡类型生成并返回不同的咖啡对象
    public Coffee orderCoffee(String type){
        Coffee coffee=null;
        if ("america".equals(type)){
            coffee=new AmericaCoffee();
        }else if ("latte".equals(type)){
            coffee=new LatteCoffee();
        }
        //添加配料
        coffee.addMilk();
        coffee.addSugar();
        return coffee;
    }

}

package com.linghu.demo10;

/**
 * 美式咖啡
 * @author linghu
 * @date 2024/2/5 16:24
 */
public class AmericaCoffee extends Coffee{

    @Override
    public String getName() {
        return "美式咖啡";
    }
}

package com.linghu.demo10;

/**
 * @author linghu
 * @date 2024/2/5 16:29
 */
public class LatteCoffee extends Coffee{

    @Override
    public String getName() {
        return "拿铁咖啡";
    }
}

package com.linghu.demo10;

/**
 * @author linghu
 * @date 2024/2/5 16:38
 */
public class Client {
    public static void main(String[] args) {
        //1、创建咖啡店类
        CoffeeStore store=new CoffeeStore();
        //2、点咖啡
        Coffee orderCoffee = store.orderCoffee("america");

        System.out.println(orderCoffee.getName());
    }
}

简单工厂模式
结构

简单工厂模式包含结构如下:

  • 抽象产品:定义了产品的规范,描述了产品的主要特征和功能。
  • 具体产品:实现或者继承抽象产品的子类。
  • 具体工厂:提供创建产品的方法,调用者通过该方法获取产品。

实现

对上述咖啡案例的改进就在于: 要将咖啡店和咖啡产品进行解耦工作,引入工厂模式。

image-20240205172116954

工厂类代码如下:

package com.linghu.demo10;

/**
 * 这个工厂就负责制造咖啡,里面没有咖啡产品,你要替换咖啡
 * 产品,不需要动这里的代码,这就实现了咖啡店和咖啡产品的解耦!
 * 咖啡店只需要调用这个工厂就可以生产咖啡了,不需要关注咖啡产品了!
 * @author linghu
 * @date 2024/2/5 17:11
 */
public class SimpleCoffeeFactory {
    public Coffee createCoffee(String type){
        Coffee coffee=null;
        if ("americano".equals(type)){
            coffee=new AmericaCoffee();
        }else if ("latte".equals(type)){
            coffee=new LatteCoffee();
        }
        return coffee;
    }
}

法,调用者通过该方法获取产品。


实现

对上述咖啡案例的改进就在于: 要将咖啡店和咖啡产品进行解耦工作,引入工厂模式。

[外链图片转存中…(img-EbAXEhcI-1711960898263)]

工厂类代码如下:

package com.linghu.demo10;

/**
 * 这个工厂就负责制造咖啡,里面没有咖啡产品,你要替换咖啡
 * 产品,不需要动这里的代码,这就实现了咖啡店和咖啡产品的解耦!
 * 咖啡店只需要调用这个工厂就可以生产咖啡了,不需要关注咖啡产品了!
 * @author linghu
 * @date 2024/2/5 17:11
 */
public class SimpleCoffeeFactory {
    public Coffee createCoffee(String type){
        Coffee coffee=null;
        if ("americano".equals(type)){
            coffee=new AmericaCoffee();
        }else if ("latte".equals(type)){
            coffee=new LatteCoffee();
        }
        return coffee;
    }
}

举报

相关推荐

0 条评论