单例设计模式、简单工厂模式、工厂模式、抽象工厂模式、装饰器模式、代理模式、模板模式的讲解

学习笔记输出来源:拉勾教育Java就业急训营
图片来源:csdn博主:Momeney 、拉勾教育

修改时间:2021年1月10日
作者:pp_x
邮箱:pp_x12138@163.com

设计模式

单例设计模式

基本概念

  • 保证一个类最多只能有一个对象,分为懒汉式和饿汉式,其中懒汉式需要对多线程进行同步处理

饿汉式

/**
 * 饿汉式单例模式
 */
public class Singleton_1 {
    private static Singleton_1 singleton_1 = new Singleton_1();
    private Singleton_1(){}
    public static Singleton_1 getInstance(){
        return singleton_1;
    }
}

懒汉式

public class Singleton {
	//懒汉式  会产生线程问题
    //2、声明本类类型的引用并执行本类类型的对象,使用private static修饰
    private static Singleton singleton = null;
    //1、私有化构造方法,使用private修饰
    private Singleton(){

    }
    //3、提供公有化get方法将上述对象返回出去
   public Singleton getSingleton(){
        if (singleton == null){
            Singleton singleton = new Singleton();//创建对象会耗费时间 此时其他线程会同时new对象
        }
        return singleton;
    }
}
线程安全型懒汉式
public class Singleton {
    //2、声明本类类型的引用并执行本类类型的对象,使用private static修饰
    //懒汉式  会产生线程问题
    private static Singleton singleton = null;
    //1、私有化构造方法,使用private修饰
    private Singleton(){    }
    //3、提供公有化get方法将上述对象返回出去
   //防止多线程问题干扰
    public Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    Singleton singleton = new Singleton();//创建对象后返回引用
                }
            }
        }
        return singleton;
    }
}

简单工厂模式(静态工厂模式)

基本概念

  • 建立一个工厂类,对实现了同一接口的不同实现类进行实例的创建
  • 当方法为静态时,也可叫静态工厂模式

类图

在这里插入图片描述

特点

  • 优点:代码简单,可读性强
  • 缺点:出现新产品需要对工厂类进行修改(方法的增加),违反了设计原则的开闭原则

产品接口

public interface Sender {
    void send();
}

产品实现类:sms发送

public class SmsSender implements Sender {
    @Override
    public void send() {
        System.out.println("sms发送");
    }
}

产品实现类:mail发送

public class MailSender implements Sender {
    @Override
    public void send() {
        System.out.println("main发送");
    }
}

产品工厂类:用于创建产品实现类的对象

package com.lagou.swdl.factory;

public class SenderFactory {
    //自定义成员方法实现
    //方式一:
    /*public Sender getSender(String type){
        if ("sms".equalsIgnoreCase(type)){
            Sender sender = new SmsSender();
            return sender;
        }
        if ("mail".equalsIgnoreCase(type)) {
            Sender sender = new MailSender();
            return sender;
        }
        return null;
    }*/
   /* //方式二:多个工厂方法
    public Sender getSms(){
        return new SmsSender();
    }
    public Sender getMail(){
        return new MailSender();
    }*/
    //静态工厂模式
    public static Sender getSms(){
        return new SmsSender();
    }
    public static Sender getMail(){
        return new MailSender();
    }
}

测试类

public class SendFactoryTest {
    public static void main(String[] args) {
    	//使用简单工厂方法进行创建
        //缺点:代码复杂 可读性差
        //优点:扩展性强 可维护性强  创建大量对象的前提下
        SenderFactory senderFactory = new SenderFactory();
        /*Sender sms = senderFactory.getSender("sms");
        sms.send();*/
        //使用静态工厂方法进行对象的创建
        SenderFactory.getSms();
        SenderFactory.getMail();
        
        //直接创建实现类对象并进行方法的调用
        //优点: 代码简单 可读性强  创建单个对象时
        //缺点:扩展性差 可维护性差
        Sender sender = new SmsSender();
        sender.send();
    }
}

工厂模式

基本概念

  • 设计一个工厂接口,每一个产品的工厂有一个单独的工厂实现类,通过自己的工厂实现类,一个工厂生产一种对应的产品

类图

在这里插入图片描述

特点

  • 优点:隐藏了产品被实例化的细节,当有新产品增加时,只需要增加一个工厂类和产品类即可,无需修改原本的代码,符合开闭原则
  • 缺点:每增加一个产品都需要成对的增加一个产品类和工厂类,增加了系统的复杂度

:产品接口和产品实现类类与简单工厂模式相同

工厂接口

public interface SenderFactory {
    Sender getSend();
}

工厂实现类:sms工厂

public class SmsSendFactory implements SenderFactory{

    @Override
    public Sender getSend() {
        return new SmsSender();//返回一个产品对象
    }
}

工厂实现类:mail工厂

public class MailSendFactory implements SenderFactory{
    @Override
    public Sender getSend() {
        return new MailSender();
    }
}

测试类

package com.lagou.swdl.factory2;

public class SendFactoryTest {
    public static void main(String[] args) {
        //声明sms工厂类型的引用并指向sms工厂类型的对象
        SmsSendFactory smssendFactory = new SmsSendFactory();
        //声明mail工厂类型的引用并执行mail工厂类型的对象
        MailSendFactory mailSendFactory = new MailSendFactory();
        //调用工厂的获取对象的方法并调用该对象发送消息的方法
        smssendFactory.getSend().send();
        mailSendFactory.getSend().send();
    }
}

抽象工厂模式

基本概念

  • 如果需要生产一个产品族(即多个产品、多个业务组成的),则需要使用抽象工厂模式
  • 例如:我需要用xx手机发xx消息,手机为一个产品 消息为一个产品

类图

特点

  • 优点:符合开闭原则,当一个产品族中多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象
  • 缺点:产品等级结构扩展难度较大

:Sender类参照以上模式

手机接口

public interface Phone {
    void use();
}

华为手机

public class HuaweiPhone implements Phone{

    @Override
    public void use() {
        System.out.println("我使用华为手机");
    }
}

小米手机

public class XiaoMiPhone implements Phone{
    @Override
    public void use() {
        System.out.println("我是用小米手机");
    }
}

抽象工厂

public interface AbstractFactory {
    Sender getSender();
    Phone getPhone();
}

小米手机装mail的工厂

public class MiMailFactory implements AbstractFactory{
    @Override
    public Sender getSender() {
        return new MailSender();
    }

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

华为手机装SMS的工厂

public class HSFactory implements AbstractFactory{

    @Override
    public Sender getSender() {
        return new SmsSender();
    }
    @Override
    public Phone getPhone(){
        return new HuaweiPhone();
    }
}

测试

public class Test {
    public static void main(String[] args) {
        //小米手机发送Mail
        MiMailFactory mimailfactory = new MiMailFactory();
        Phone xiaomi = mimailfactory.getPhone();
        Sender mail = mimailfactory.getSender();
        xiaomi.use();
        mail.send();

        //华为手机发送SMS
        HSFactory hsFactory = new HSFactory();
        Phone huawei = hsFactory.getPhone();
        Sender sms = hsFactory.getSender();
        huawei.use();
        sms.send();
    }
}

三个工厂的联系与区别

  • 当只需要生产一种产品时,抽象工厂等价于工厂模式;当将所有同一个产品交给一个具体的工厂生产时,工厂模式等价于简单工厂模式

装饰器模式

基本概念

  • 装饰器模式就是给一个对象动态的增加一些新功能,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。

类图

在这里插入图片描述
接口


public interface Sourceable {
    void method();
}

被修饰的类

public class Source implements Sourceable {
    @Override
    public void method() {
        System.out.println("被装饰的类");
    }
}

装饰类

public class Decorator implements Sourceable{
    private Sourceable source;
    public Decorator(Sourceable source){//多态的引用  传参的时候传Source对象的引用
        this.source = source;
    }
    @Override
    public void method() {
        source.method();
        System.out.println("修饰以后");
    }
}

测试类

public class SourceTest {
    public static void main(String[] args) {
        //没有装饰的情况下
        Sourceable sourceable = new Source();
        sourceable.method();

        //装饰
        Sourceable sourceable1 = new Decorator(sourceable);
        sourceable1.method();
    }
}

结果

被装饰的类
修饰以后

实际意义

  • 实现一个类的功能扩展
  • 动态地实现增加,增加后还能撤销
  • 缺点:会产生过多的相似类,不易排错,可读性略差

装饰模式和继承的区别

经常会有一个疑问,为什么装饰模式里调用了被修饰类的方法,使得在被修饰类不被改变的前提下,拥有新的功能,而这种形式在及成立也可以用super.的方法来实现,那为什么还要多此一举用装饰模式来构造代码呢?

  • 下面有一个自己对此的见解,为什么装饰器比继承好

以抄写东西为例(稍微有些许不妥当),不论我抄写什么,都得实现一个写的接口,而如果用黑笔写,就得新建一个黑笔写字类实现写接口,用红笔写就得新建一个红笔写类来实现写接口,而如果为了提高写的速度,发明了一个能加快速度的工具,那么此时想加快抄写速度,则需要再继续继承各自颜色的笔,最后会形成下面的这种结构

  Write
	|-- RedWirte
			|-- QuickRedWrite
	|-- BlackWrite
			|-- QuickBlackWrite

而如果此时想再增加笔的颜色,则需要再添加一个父子类实现自Write接口,不光会使添加代码量过多,还会使得系统臃肿。

  Write
	|-- RedWirte
			|-- QuickRedWrite
	|-- BlackWrite
			|-- QuickBlackWrite
	|-- BlackWrite
			|-- QuickBlackWrite

而如果像提取写这个共同状态一样将,加速工具提取出来,创建一个新的类并实现写的接口,形成一个快速写类即可,需要的时候加上,不需要的时候卸下来,那么就形成了一个装饰模式。此时代码结构如下:

Write
	|-- RedWirte
	|-- BlackWrite
	|-- BlackWrite
    |-- QuickWrite(Write write)

代理模式

基本概念

  • 代理模式就是找一个代理类替原对象进行一些操作。
  • 比如我们在租房子的时候找中介,再如我们打官司需要请律师,中介和律师在这里就是我们的代理

类图

在这里插入图片描述

:Sourceable类和Source类同上
代理类

package com.lagou.swdl.proxy;

import com.lagou.swdl.decorator.Source;
import com.lagou.swdl.decorator.Sourceable;

public class Proxy implements Sourceable {
    private Source source;
    public Proxy(){
        source = new Source();
    }
    @Override
    public void method() {
        source.method();
        System.out.println("我和装饰器不一样");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        Sourceable sourceable = new Proxy();
        sourceable.method();
    }
}

结果

被装饰的类
我和装饰器不一样

实际意义

  • 如果在使用的时候需要对原有的方法进行改进,可以采用一个代理类调用原有方法,并且对产生的结果进行控制,这种方式就是代理模式。
  • 使用代理模式,可以将功能划分的更加清晰,有助于后期维护。

代理模式和装饰模式的区别

  • 装饰器模式通常的做法是将原始对象作为一个参数传给装饰者的构造器,而代理模式通常在一个代理类中创建一个被代理类的对象。
  • 装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。
  • 代理模式与装饰器模式有何区别?

模板模式

基本概念

  • 模板方法模式主要指一个抽象类中封装了一个固定流程,流程中的具体步骤可以由不同子类进行不同的实现,通过抽象类让固定的流程产生不同的结果

类图

在这里插入图片描述
模板类

public abstract class AbstractCalculator {
    //自定义成员方法实现将参数指定的表达式按照参数指定的规则进行切割并返回计算结果
    public int splitExpression(String str,String op){
        String[] arr = str.split(op);
        return calculate(Integer.parseInt(arr[0]),Integer.parseInt(arr[1]));
    }
    public abstract int calculate(int a,int b);

}

实现模板功能类

public class Plus extends AbstractCalculator {
    @Override
    public int calculate(int a, int b) {
        return  a + b;
    }
}

实现模板功能类二

public class Minus extends AbstractCalculator {
    @Override
    public int calculate(int a, int b) {
        return a - b;
    }

测试类

public class AbstractCalculatorTest {
    public static void main(String[] args) {
        AbstractCalculator abstractCalculator = new Plus();
        int i = abstractCalculator.splitExpression("1+1", "\\+");
        AbstractCalculator abstractCalculator1 = new Minus();
        int j = abstractCalculator1.splitExpression("1-1", "\\-");
        System.out.println(i+" "+j);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值