GOF 的23种JAVA常用设计模式 大白话 23种设计模式

前言:

设计模式,前人总结下留给后人更好的设计程序,为我们的程序代码提供一种思想与认知,如何去更好的写出优雅的代码,23种设计模式,是时候需要掌握它了。

 

 

1.工厂模式

大白话:比如你需要一辆汽车,你无需了解汽车是怎么样生产的,你只需要告诉汽车厂,我要买某某某型号的汽车,?,汽车厂造好了给你即可。这就是工厂模式:

隐藏具体对象实例的过程,只需要告诉这个工厂你想要的东西(对象) 它帮你实现,你不必关系具体的实现过程;

 

举个经常用到的例子:

 

  1. 数据库连接当中指明你的数据库类型:mysql
  2. 数据库分页插件当中的方言

实践:

1、创建一个汽车工厂接口

/**
 * 汽车生产工厂
 */
public interface CarFactory {
    //创造汽车方法
    void createCar();

}

 

2、使用三个不同的类实现工厂方法

public class DazoCar implements CarFactory {

    @Override
    public void createCar() {
        System.out.println("生产大众汽车");
    }
}
public class BYDCar implements CarFactory {

    @Override
    public void createCar() {
        System.out.println("生产BYD汽车");
    }
}
public class BenciCar implements CarFactory {

    @Override
    public void createCar() {
        System.out.println("生产奔驰汽车");
    }
}

 

3、创建一个汽车工厂

public class Factory {


    public static CarFactory getCarFactroy(String type){

        //大众
        if ("DAZO".equals(type)) {
            return new DazoCar();
        } else if ("BYD".equals(type)) {
            //BYD
            return new BYDCar();
        } else if ("BENCI".equals(type)){
            //奔驰
            return new BenciCar();
        }
        return null;
    }
}

4、测试调用

    public static void main(String[] args) {

        CarFactory carFactory = Factory.getCarFactroy("BYD");

        carFactory.createCar();

    }

 

 这就是一个最简单的工厂模式;

 

抽象工厂

大白话:比如小米工厂就是一个最大的抽象工厂,它里面不仅有生产手机的工厂,也有生产家用小米电器的工厂,工厂里面套工厂,这就是抽象工厂

就按照这个例子,有一家抽象工厂,它可以有生产手机和生产电器的工厂,它的工厂有具体的实现类(小米或者华为的工厂)

 

1、创建一个生产手机的工厂

 

public interface PhoneFactory {

    //生产方法
    void create();
}

 

2、创建一个生产电器的工厂

//电器工厂,生产电器
public interface DianFactory {

    //创造电器
    void createDian();

}

 

3、创建一个抽象工厂,这个抽象工厂可以同时生产电器、手机

public abstract class Factory {

    //获取手机工厂
    public abstract PhoneFactory getPhoneFactory(String type);

    //获取电器工厂
    public abstract DianFactory getDianFactory(String type);

}

 

4、具体的抽象工厂继承类 比如小米可以生产、华为也可以生产

//小米工厂
public class XiaoMiFactory extends Factory {

    @Override
    public PhoneFactory getPhoneFactory(String type) {
        return new XiaomiPhone();
    }

    @Override
    public DianFactory getDianFactory(String type) {
        return new XiaoMiDian();
    }
}

小米手机的工厂生产小米手机、小米电器

public class XiaomiPhone implements PhoneFactory {

    @Override
    public void create() {
        System.out.println("小米手机");
    }
}
public class XiaoMiDian implements DianFactory {

    @Override
    public void createDian() {
        System.out.println("小米生产电器");
    }
}

 

同理、华为也可以继承工厂类、它也可以生产手机和电器

public class HuaWeiFactory extends Factory {

    @Override
    public PhoneFactory getPhoneFactory(String type) {
        return new HuaWeiPhone();
    }

    @Override
    public DianFactory getDianFactory(String type) {
        return new HuaWeiDian();
    }
}

 

public class HuaWeiPhone implements PhoneFactory {

    @Override
    public void create() {
        System.out.println("生产华为手机");
    }
}

 

public class HuaWeiDian implements DianFactory {

    @Override
    public void createDian() {
        System.out.println("华为电器");
    }
}

 

5.创建一个工厂调度器,来取出需要的工厂

public class FactoryProducer {

    //按照名称获取工厂
    public static Factory getFactory(String name){

        if ("XIAOMI".equals(name)) {
            return new XiaoMiFactory();
        } else if ("HUAWEI".equals(name)) {
            return new HuaWeiFactory();
        }
        return null;
    }
}

 

最后我们main方法测试,传入HUAWEI, 则调出的是华为工厂,然后调用华为生产手机或者华为生产电器即可

public static void main(String[] args) {


        Factory factory = getFactory("HUAWEI");

        PhoneFactory phoneFactory = factory.getPhoneFactory(null);

        phoneFactory.create();

    }

 

单例模式

大白话:所谓单例模式,就是这个类在你的系统中只作为一个的存在,是为了防止重复的创造对象、销毁对象所带来的内存的开销。并且在这个类当中提供一个全局访问点

主要解决:一个全局使用的类频繁地创建与销毁。

何时使用:当您想控制实例数目,节省系统资源的时候。

 

举个栗子:

大家都知道我们用SpringBoot作为服务端,向前台返回数据的时候,一般返回的都是JsonObject

这个Object所有的控制器返回数据都可以用到,我们这里就可以考虑用单例模式来初始化这个类,

单例模式在这里分为好几个模块;

  • 懒汉式
  • 饿汉式(最常用)在初始化类的时候就初始化成员变量
public class JsonObject {

    private static Map<String,Object> map = new HashMap<>(16);

    //构造方法私有
    private JsonObject(){}

    //提供全局访问点 synchronized(线程安全)
    public static synchronized Object resultOk(Object data){
        map.clear();

        map.put("status","ok");
        map.put("data",data);
        map.put("msg","请求成功");

        return map;
    }

    //提供全局访问点
    public static synchronized Object resultError(String msg){
        map.clear();

        map.put("status","ok");
        map.put("data",null);
        map.put("msg",msg);

        return map;
    }

}

 

我们尝试这调用

    public static void main(String[] args) {
        System.out.println(JsonObject.resultError("密码不能为空"));
        System.out.println(JsonObject.resultOk("192.168.0.1"));
    }

 

 

 

这样就完成了一个饿汉式(常用)的一种单例模式

 

建造者模式

大白话:将一个庞大的系统拆分成小份、小份之间互不影响、小份有者同样的制造过程,这就是建造者模式

 

举个例子:

我们去肯德基吃快餐, 肯定有它店铺的套餐可以供我们选择,套餐就是庞大的系统,套餐里面最简单的有:汉堡、饮料(组成小份),他们可以任意搭配组成不同的价格

小份有着相同的制造过程,比如汉堡用纸盒包装/饮料用瓶子包装,这里的包装就是建造过程。

 

何时使用:一些基本部件不会变,而其组合经常变化的时候。

测试代码:

//一个商品的超类接口

//单品接口
public interface Item {

    //单品名称
    String name();

    //价格
    Double price();

    //打包方式
    Packing pack();

}

//商品有各自的打包方式 创建一个打包的接口

//包装方式
public interface Packing {

    //打包方式
    String packing();

}

// 汉堡实现商品的接口 并且完善自己的打包方式;

public class Hanbao implements Item {

    @Override
    public String name() {
        return "汉堡";
    }

    @Override
    public Double price() {
        return 21.00;
    }

    @Override
    public Packing pack() {
        return new HeZhuang();
    }
}

//汉堡是盒装

public class HeZhuang implements Packing {

    @Override
    public String packing() {
        return "盒装";
    }
}

 

//可乐实现商品接口

public class Kele implements Item {

    @Override
    public String name() {
        return "可乐";
    }

    @Override
    public Double price() {
        return 5.00;
    }

    @Override
    public Packing pack() {
        return new PingZhuang();
    }
}

 

//可乐独有的打包方式

public class PingZhuang implements Packing {

    @Override
    public String packing() {
        return "瓶装";
    }
}

//建造者模式提供一个菜单组合 用于组合想要的单品组成套餐

 

public class ItemList {

    private List<Item> list = new ArrayList<>();

    //增加一个套餐
    public void addItem(Item item){
        list.add(item);
    }

    //组合总价
    public Double getPrice(){

        Double price = 0.00;

        for (Item item : list) {
            price+= item.price();
        }
        return price;
    }
    //组合详情
    public void detail() {
        for (Item item : list) {

            System.out.print(item.name()+"-->");
            System.out.print(item.price()+"-->");
            System.out.print(item.pack().packing()+"-->");
        }

    }

}

 

//开始测试

public class Main {

    public static void main(String[] args) {
        System.out.print(no1().getPrice());
        no1().detail();
        System.out.println("");
        no2().detail();
        System.out.print(no2().getPrice());


    }

    //套餐一 汉堡2 + 可乐1
    public static ItemList no1(){

        Hanbao hanbao = new Hanbao();
        Hanbao hanbao2 = new Hanbao();

        Kele kele = new Kele();

        ItemList list = new ItemList();

        list.addItem(hanbao);
        list.addItem(hanbao2);
        list.addItem(kele);

        return list;
    }


    //套餐二 汉堡1 + 可乐2
    public static ItemList no2(){

        Hanbao hanbao = new Hanbao();

        Kele kele = new Kele();
        Kele kele2 = new Kele();

        ItemList list = new ItemList();

        list.addItem(hanbao);
        list.addItem(kele2);
        list.addItem(kele);

        return list;
    }

}

 

这里用连个方法组合了两个套餐,这就是建造者模式 ,

 

原型模式

大白话:用于创建重复的对象,用克隆对象的方式代替new 关键字的使用。

 

 

//对象实现Cloneable 重写父类的clone方法

public class Student implements Cloneable {

    private String id;

    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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


    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }

}

 

//测试 分别用new的方式与clone的方式 创建100个相同的对象需要的毫秒数

public static void main(String[] args) {

        long start = System.currentTimeMillis();
        System.out.println(start);

        for (int i = 0;i<100;i++) {

            Student student = new Student();
            student.setId("1");
            student.setName("mrc");

            System.out.println(student.getId());
            System.out.println(student.getName());
        }

        long end = System.currentTimeMillis();
        System.out.println(end);

        System.out.println("总耗时:"+(end-start));


    }

 

 

//通过克隆的方式创造相同的对象进行测试

public static void main(String[] args) {

        long start = System.currentTimeMillis();
        System.out.println(start);

        Student student = new Student();
        student.setId("1");
        student.setName("mrc");

        for (int i = 0;i<100;i++) {

            Student student1 = (Student) student.clone();

            System.out.println(student1.getId());
            System.out.println(student1.getName());
        }

        long end = System.currentTimeMillis();
        System.out.println(end);

        System.out.println("总耗时:"+(end-start));


    }

 

 

果然性能上还是有差距的

 

适配器模式

大白话:我们现在应用写的接口是TF卡接口 现在我们要用接口对接到电脑的USB上,这时候怎么办,我们就需要一个读卡器(适配器)既有USB接口,又有TF卡接口 这就是一个适配器

 


这里我们来模拟:定义一个USB接口

public interface USBInterface {

    //读取
    void read();

    //写入
    void write();

}

//USB2.0实现接口

public class USB20 implements USBInterface {


    @Override
    public void read() {
        System.out.println("USB2.0读取");
    }

    @Override
    public void write() {
        System.out.println("USB2.0写入");
    }
}

//定义一个电脑接口

public interface Computer {

    //电脑可以读取USB
    void readUsb(USBInterface usbInterface);

}

//用惠普电脑去实现电脑

public class HpComputer implements Computer {

    @Override
    public void readUsb(USBInterface usbInterface) {
        usbInterface.read();
    }
}

##

这时候就可以测试一个USB在电脑上的读取了

    public static void main(String[] args) {


        USBInterface usb20 = new USB20();

        Computer computer = new HpComputer();

        computer.readUsb(usb20);


    }

 

 

 

现在需要把TF卡接入到USB接口上 但是TF接口与USB不适合 需要中间要有一个适配器

//TF卡接口
public interface TF {
    //读取TF卡
    void readTF();
    //写入TF卡
    void writeTF();
}

 

//这里需要一个闪迪作为TF卡的实现

public class SanDiskTF implements TF {
    @Override
    public void readTF() {
        System.out.println("闪迪卡读取");
    }
    @Override
    public void writeTF() {
        System.out.println("闪迪卡写入");
    }
}

 

//接入适配器,把TF卡接入到USB接口上

public class USBAdapterTF implements USBInterface {

    //将TF卡作为属性引入
    private TF tf;

    public USBAdapterTF(TF tf){
        //构造器进行桥接
        this.tf = tf;
    }

    @Override
    public void read() {
        tf.readTF();
    }

    @Override
    public void write() {
        tf.writeTF();
    }
}

//测试使用适配器让电脑读取TF卡

    public static void main(String[] args) {
        Computer computer = new HpComputer();
        TF tf = new SanDiskTF();
        //USB适配器
        USBInterface usbAdapterTF = new USBAdapterTF(tf);
        //电脑读取
        computer.readUsb(usbAdapterTF);
    }

 

桥接模式

大白话:我们一般先定义接口,再做实现类对吧,需要加一个接口定义的话,实现类必须实现这个方法,桥接模式就是这两种类型即使改变了结构也不会受到影响。

 

//定义一个画图的接口

public interface DrawImg {

    void draw();

}

 

//再用画出红色去实现这个接口

public class DrawRed implements DrawImg {

    @Override
    public void draw() {
        System.out.println("画出红色");
    }
}

 

//用一个中间抽象层代替直接实现 抽象层引用需要实现的方法即可

public abstract class Shape {

    protected DrawImg drawImg;

    protected Shape(DrawImg drawImg){
        this.drawImg = drawImg;
    }
    //抽象衔接
    public abstract void draw();

}

 

//具体的类再去继承这个抽象方法 引用父类里面接口的属性

public class Circle extends Shape {

    protected Circle(DrawImg drawImg) {
        super(drawImg);
    }

    @Override
    public void draw() {
        drawImg.draw();
    }
}

 

//实现桥接

public static void main(String[] args) {
        DrawImg drawImg = new DrawRed();
        Circle circle = new Circle(drawImg);
        circle.draw();
    }

 

 

 

 

 

 

 

 

 

 

持续更新中。。。。

 

参考:

菜鸟教程:https://www.runoob.com/design-pattern/design-pattern-tutorial.html

 

转载于:https://www.cnblogs.com/ChromeT/p/11503186.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值