设计模式

 

来源:https://www.bilibili.com/video/BV1mc411h719?from=search&seid=16647315943328944616

哔哩哔哩:狂神说

菜鸟教程设计模式

面试必备:常用的设计模式总结

设计模式的七大原则

1、开闭原则(Open Close Principle)

开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

继承时候,尽量添加新的方法,不要改变父类原有的功能,重写父类方法,会使继承体系的可复用性变差。

3、依赖倒转原则(Dependence Inversion Principle)

这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。

5、迪米特法则,又称最少知道原则(Demeter Principle)

最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。

创建型模型:单例模式,工厂模式,抽象工厂模式,建造者模式,原型模式

单例模式:

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

饿汉式单例:

直接使用final,多线程安全,可能会造成空间浪费,是否 Lazy 初始化

package danlimoshi;
//饿汉式单例
//单例模式构造器私有
public class Hungry {

//    饿汉模式,先将下面的对象加载进内存,可能会浪费空间
    private  byte[] data1 = new byte[1024*1024];
    private  byte[] data2 = new byte[1024*1024];
    private  byte[] data3 = new byte[1024*1024];
    private  byte[] data4 = new byte[1024*1024];
    private Hungry(){

    }
    private final static Hungry HUNGRY = new Hungry();

    public static Hungry getHungry() {
        return HUNGRY;
    }
}

懒汉式单例:

 

懒汉式多线程不安全的版本,懒加载:

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
  
    public static Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}

为什么多线程不安全呢?

lazyMan = new LazyMan();
                    /**
                     * new LazyMan()不是原子操作,执行过程中会执行下面三步操作,并且执行顺序不一定,比如执行顺序为1,3,2,执行完1,3后,一个线程抢占了资源,此时实例对象不是null,但是它也确实是没有完成实例化,会出问题。
                     * 1、虚拟机为对象分配内存空间
                     * 2、执行构造方法,初始化对象
                     * 3、把这个对象指向这个空间
                     */

Java中New一个对象是个怎么样的过程?

懒汉式多线程安全的版本懒加载 使用同步返回实例对象的方法:

深入理解Java并发之synchronized实现原理

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}

懒汉式多线程安全,并且能够防止一部分反射破坏的版本。懒加载

例子中包含了解决多线程不安全的办法:双重检测锁模式的懒汉单例,DCL懒汉模式,还包含了如何使用标志位“密码”来防止用户使用反射创建多个实例对象。但是用户还可以通过反射修改标志位“密码”,还是可以创建多个单例。

package danlimoshi;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

//懒汉式单例模式
//https://www.bilibili.com/video/BV1K54y197iS
public class LazyMan {

//    Java 语言提供了 volatile 和 synchronized 两个关键字来保证线程之间操作的有序性,
//    volatile 是因为其本身包含“禁止指令重排序”的语义,
//    synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,
//    此规则决定了持有同一个对象锁的两个同步块只能串行执行。

    private volatile static LazyMan lazyMan;

//  一个防止别人使用反射破坏的“密码”,名字很重要,名字暴露之后,可以通过反射修改这个“密码”继续破坏,还是能生成多个实例对象
    private static boolean jiamihouodebiaoqian = false;
    private LazyMan(){
        synchronized (LazyMan.class){
            if(jiamihouodebiaoqian == false){
                jiamihouodebiaoqian = true;
            }
            else{
                throw new RuntimeException("不要试图使用反射");
            }
//            防止使用getLazyMan后再使用反射
//            if(lazyMan!=null){
//                throw new RuntimeException("不要试图使用反射");
//            }
        }

    }



//    双重检测锁模式的懒汉单例,DCL懒汉模式
    public static LazyMan getLazyMan(){
//        此处判断是为提升性能
        if (lazyMan ==null){
            synchronized (LazyMan.class){
                if (lazyMan ==null) {
                    lazyMan = new LazyMan();
                    /**
                     * new LazyMan()不是原子操作
                     * 1、分配内存空间
                     * 2、执行构造方法,初始化对象
                     * 3、把这个对象指向这个空间
                     */

                }
            }
        }
        return lazyMan;
    }
//    单线程下没有问题,多线程就有问题了
//    public static void main(String[] args){
//        for (int i = 0; i < 10; i++) {
//            new Thread(()->{
//                LazyMan.getLazyMan();
//            }).start();
//        }
//    }

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

//        LazyMan lazyMan = LazyMan.getLazyMan();
//        LazyMan lazyMan2 = LazyMan.getLazyMan();
//        System.out.println(lazyMan==lazyMan2);//true


        //破坏加密flag:jiamihouodebiaoqian
        Field jiamihouodebiaoqian = LazyMan.class.getDeclaredField("jiamihouodebiaoqian");
        //不检查私有的变量,让反射机制可以访问私有变量
        jiamihouodebiaoqian.setAccessible(true);

        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        //       无视私有构造器
        declaredConstructor.setAccessible(true);
        LazyMan lazyMan1 = declaredConstructor.newInstance();


        //获取第一个实例对象后,修改“密码”标志位,再次调用反射
        //通过反射写入属性
        jiamihouodebiaoqian.set(lazyMan1,false);
        LazyMan lazyMan3 = declaredConstructor.newInstance();

        System.out.println(lazyMan1==lazyMan3);

    }
}

双检锁/双重校验锁(DCL,即 double-checked locking)

多线程安全,并且多次判断是否为null,能够保持性能,懒加载

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}

登记式/静态内部类

多线程安全,并且懒加载

package danlimoshi;

//静态内部类
//只要是单例模式就要构造器私有

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Holder {
    private Holder(){

    }

    public static class  Innerclass{
        private static final Holder HOLDER = new Holder();
    }
    public static Holder getInstance(){
//       ,反射就给破解了
        return Innerclass.HOLDER;
    }


}

枚举

枚举不会被反射破坏

package danlimoshi;

import java.lang.reflect.Constructor;

//枚举本身是一个class
//反射不能破坏枚举
public enum EnumSing {
    INSTANCE;

    public EnumSing getInstance(){
        return INSTANCE;
    }

}

class Test{
    public static void main(String[] args) throws Exception{
        EnumSing instance1 = EnumSing.INSTANCE;
//        枚举的构造器是有参数的
        Constructor<EnumSing> declaredConstructor = EnumSing.class.getDeclaredConstructor(String.class,int.class);
        declaredConstructor.setAccessible(true);
        EnumSing instance2 = declaredConstructor.newInstance();

        System.out.println(instance1==instance2);
    }
}

工厂模式:

简单工厂和抽象工厂,在增加新产品的时候都违反了开闭原则,只有工厂方法模式遵从了开闭原则,在实际应用时,根据实际情况,如果产品稳定,不经常

这张图概括了后面工厂模式的全部

工厂模式

简单工厂模式:不满足开闭原则

有car接口,他的实现类有WuLing,Tesla,工厂类CarFactory,调用工厂的类Customer

package factory.simple;

public interface Car {
    void car();
}
package factory.simple;

public class WuLing implements Car{
    @Override
    public void car() {
        System.out.println("五菱宏光");
    }
}
package factory.simple;

public class Tesl implements Car{
    @Override
    public void car() {
        System.out.println("特斯拉");
    }
}
package factory.simple;


//简单工厂模式、静态工厂模式 //都使用静态方法
//不满足开闭原则,如果想满足开闭原则,会多付出很多代价


/**
 * 如果此时多了一个新的车,如何加进去
 * 1、修改getCar(),违反开闭原则
 * 2、使用getWuLing(),getTesla()的方式创建Car对象,还是会修改CarFactory的类
 */
public class CarFactory {
    public static Car getCar(String car){
        if(car.equals("五菱")){
            return new WuLing();
        }else if(car.equals("Tesla")){
            return new WuLing();
        }else{
            return null;
        }
    }
}
package factory.simple;

public class Customer {
    public static void main(String[] args) {
//        不使用工厂
        Car car1 = new WuLing();
        Car car2 = new Tesl();
        System.out.println(car1);
        System.out.println(car2);

//        使用工厂
        Car car3 = CarFactory.getCar("五菱");
        Car car4 = CarFactory.getCar("Tesla");
        System.out.println(car3);
        System.out.println(car4);
    }
}

工厂方法模式:

还是上面的Car类,每个车有自己的工厂类,这些类都实现了各自的工厂接口,当有一个新的车时,只需创建他的实体类与工厂类,不需要修改代码,符合了开闭原则,但是每个车的实体类都需要一个工厂类,代价比较大。
package factory.method;

//工厂方法模式
public interface CarFactory {
    Car getCar();
}
package factory.method;

public class TeslaFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new Tesl();
    }
}
package factory.method;

public class WuLingFactory implements CarFactory{
    @Override
    public Car getCar() {
        return new Tesl();
    }
}
package factory.method;

import factory.simple.CarFactory;
import factory.simple.WuLing;

/**
 * 工厂方法模式
 * 每个车有自己的工厂类,这些类都实现了工厂接口
 */
public class Customer {
    public static void main(String[] args) {
        Car car1 = new WuLingFactory().getCar();
        Car car2 = new TeslaFactory().getCar();
        System.out.println(car1);
        System.out.println(car2);
    }
}

简单工厂模式与工厂方法模式对比

抽象工厂模式

 

产品组和产品等级结构

来源:https://blog.csdn.net/liuyuchen282828/article/details/100862118

案例的结构

案例的类图:

案例:HuaweiFactory华为的工厂,XiaomiFactory小米的工厂,HUAWEIPhone华为手机的工厂,HUAWEIRouter华为路由器的工厂,IPhoneProduct所有的手机工厂,IRouteFactory所有的路由器工厂,Client测试类。

package factory.abstract1;
//手机产品接口
public interface IphoneProdect {
    void start();
    void shutdown();
    void callup();
    void sendMS();
}
package factory.abstract1;

//路由器产品接口
public interface IRouteProduct {
    void start();
    void shutdown();
    void openwifi();
    void seeting();
}

工厂的工厂的接口IProductfactory:拥有手机产品、路由器产品的接口

package factory.abstract1;

public interface IProductfactory {
//    生产手机
    IphoneProdect iphoneProdect();
//    生产路由器
    IRouteProduct irouterProduct();
}
package factory.abstract1;

public class XiaomiFactory implements IProductfactory{
    @Override
    public IphoneProdect iphoneProdect() {
        return new XiaomiPhone();
    }

    @Override
    public IRouteProduct irouterProduct() {
        return new XiaomiRouter();
    }
}
package factory.abstract1;

public class XiaomiFactory implements IProductfactory{
    @Override
    public IphoneProdect iphoneProdect() {
        return new XiaomiPhone();
    }

    @Override
    public IRouteProduct irouterProduct() {
        return new XiaomiRouter();
    }
}

小米工厂,直接实现工厂的工厂接口就可以

package factory.abstract1;

public class XiaomiFactory implements IProductfactory{
    @Override
    public IphoneProdect iphoneProdect() {
        return new XiaomiPhone();
    }

    @Override
    public IRouteProduct irouterProduct() {
        return new XiaomiRouter();
    }
}

小米手机具体实现类:

package factory.abstract1;

//小米手机
public class XiaomiPhone implements IphoneProdect{

    @Override
    public void start() {
        System.out.println("小米手机开机");

    }

    @Override
    public void shutdown() {
        System.out.println("小米手机关机");
    }

    @Override
    public void callup() {
        System.out.println("用小米手机打电话");
    }

    @Override
    public void sendMS() {
        System.out.println("用小米手机发短信");
    }
}

小米路由器

package factory.abstract1;

public class XiaomiRouter implements IRouteProduct{
    @Override
    public void start() {
        System.out.println("启动小米路由器");
    }

    @Override
    public void shutdown() {
        System.out.println("关闭小米路由器");
    }

    @Override
    public void openwifi() {
        System.out.println("小米打开wifi");
    }

    @Override
    public void seeting() {
        System.out.println("小米设置路由器");
    }
}

华为的代码就不粘贴了

测试类:

package factory.abstract1;

public class Client {
    public static void main(String[] args) {
        System.out.println("小米系列");
//        小米工厂
       XiaomiFactory xiaomiFactory = new XiaomiFactory();
//       小米手机
       xiaomiFactory.iphoneProdect().callup();
       xiaomiFactory.iphoneProdect().sendMS();
//      小米路由器
       xiaomiFactory.irouterProduct().seeting();

//      华为工厂
        HuaweiFactory huaweiFactory = new HuaweiFactory();
//       华为手机
        huaweiFactory.iphoneProdect().callup();
        huaweiFactory.iphoneProdect().sendMS();
//      华为路由器
        huaweiFactory.irouterProduct().seeting();

    }
}

建造者模式

案例:

package factory.builder;

//抽象的建造者
public abstract class Builder {
    abstract void buildA();//地基
    abstract void buildB();//钢筋工程
    abstract void buildC();//铺电线
    abstract void buildD();//粉刷

    abstract Product getProduct();
}
package factory.builder;

//具体的构建者:工人
public class Worker extends Builder {
    private  Product product;

    public Worker(){
        product = new Product();
    }

    @Override
    void buildA() {
        product.setBuildA("地基");
        System.out.println("地基");
    }

    @Override
    void buildB() {
        product.setBuildB("钢筋工程");
        System.out.println("钢筋工程");
    }

    @Override
    void buildC() {
        product.setBuildC("铺电线");
        System.out.println("铺电线");
    }

    @Override
    void buildD() {
        product.setBuildD("粉刷墙面");
        System.out.println("粉刷墙面");
    }

    @Override
    Product getProduct() {
        return product;
    }
}
package factory.builder;

//产品:房子
public class Product {
    private String buildA;
    private String buildB;
    private String buildC;
    private String 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;
    }

    @Override
    public String toString() {
        return "Product{" +
                "buildA='" + buildA + '\'' +
                ", buildB='" + buildB + '\'' +
                ", buildC='" + buildC + '\'' +
                ", buildD='" + buildD + '\'' +
                '}';
    }
}
package factory.builder;

//指挥:核心,负责指挥构建一个工程,工程如何构建,由他决定
public class Derector {
    /**
     * 指挥工人按照顺序建房子,先建A再B再C再D的顺序
     * @param builder
     * @return
     */
    public Product build(Builder builder){
        builder.buildA();
        builder.buildB();
        builder.buildC();
        builder.buildD();
        return builder.getProduct();
    }
}
package factory.builder;

public class Test {
    public static void main(String[] args) {
//        指挥
        Derector derector = new Derector();
//        指挥工人完成产品
        Product build = derector.build(new Worker());
        System.out.println(build.toString());
    }
}

 

另一个建造者模式的案例:

没有指挥者,任务顺序由Worker控制,可以自定义“套餐”。

package factory.builder.demo02;


import java.sql.PreparedStatement;

//抽象的建造者
public abstract class Builder {
    abstract Builder buildA(String msg);//汉堡
    abstract Builder buildB(String msg);//可乐
    abstract Builder buildC(String msg);//薯条
    abstract Builder buildD(String msg);//甜点

    abstract Product getProduct();
}
package factory.builder.demo02;

//产品:套餐
public class Product {
    private String buildA = "汉堡";
    private String buildB = "可乐";
    private String buildC = "薯条";
    private String 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;
    }

    @Override
    public String toString() {
        return "Product{" +
                "buildA='" + buildA + '\'' +
                ", buildB='" + buildB + '\'' +
                ", buildC='" + buildC + '\'' +
                ", buildD='" + buildD + '\'' +
                '}';
    }
}
package factory.builder.demo02;

public class Worker  extends Builder{
    private Product product = new Product();

    @Override
    Builder buildA(String msg) {
        product.setBuildA(msg);
        return this;
    }

    @Override
    Builder buildB(String msg) {
        product.setBuildB(msg);
        return this;
    }

    @Override
    Builder buildC(String msg) {
        product.setBuildC(msg);
        return this;
    }

    @Override
    Builder buildD(String msg) {
        product.setBuildD(msg);
        return this;
    }

    @Override
    Product getProduct() {
        return product;
    }
}

 

package factory.builder.demo02;

public class Test {
    public static void main(String[] args) {
//        服务员
        Worker worker = new Worker();
//        可以在原来的基础上自由组合
        Product product = worker.buildA("鸡翅").buildB("雪碧").getProduct();
        System.out.println(product.toString());

        Product product2 = worker.getProduct();
        System.out.println(product2.toString());
    }
}

 

下一步原型模式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值