七种常用设计模式学习总结(上)


前言

通过学习设计模式的相关课件,阅读《大话设计模式》,了解了常用的七种设计模式:单例模式、工厂方法模式、抽象工厂模式、代理模式、装饰器模式、观察者模式和责任链模式。本篇博客先对软件设计模式的概述和前三种设计模式进行学习总结。

设计模式概述

设计模式分类

设计模式根据工作的目的,分为了创建型模式、结构型模式和行为型模式三类。

创建型模式:单例模式工厂方法模式抽象工厂模式、建造者模式、原型模式。
结构型模式:适配器模式、代理模式装饰器模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

软件设计七大原则(OOP七大原则)

开闭原则:对扩展开放,对修改关闭
里氏替换原则:不要破坏继承体系,子类重写方法功能发生改变,不应该影响父类方法的含义
依赖倒置原则:要面向接口编程,不要面向实现编程。
单一职责原则:控制类的粒度大小、将对象解耦、提高其内聚性。
接口隔离原则:要为各个类建立它们需要的专用接口
迪米特法则:一个类应该保持对其它对象最少的了解,降低耦合度。
合成复用原则:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。*

实际上,七大原则的目的只有一个:降低对象之间的耦合,增加程序的可复用性、可扩展性和可维护性

单例模式

定义

一个类只有一个实例,且该类能自行创建这个实例的一种模式。

特点

1.单例类只有一个实例对象;
2.该单例对象必须由单例类自行创建;
3.单例类对外提供一个访问该单例的全局访问点。

饿汉式单例

该模式的特点是类一旦加载就创建一个单例,保证在调用 getInstance 方法之前单例已经存在了。

public class Hungry {

    private Hungry() { }

    private final static Hungry HUNGRY = new Hungry();

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

但是,饿汉式单例会造成浪费空间。

懒汉式单例

为了避免内存的浪费,我们可以采用懒汉式单例,即用到该单例对象的时候再创建。

public class LazyMan {
    private LazyMan(){};

    public static LazyMan lazyMan;

    public static LazyMan getInstance(){
        if (lazyMan==null){
            lazyMan = new LazyMan();
        }
        return lazyMan;
    }
}

这是最简单的懒汉式。但是,是有很大问题的。单线程下这段代码是没有问题的,但是在多线程下就有很大问题。我们可以进行测试

	private LazyMan(){
        System.out.println(Thread.currentThread().getName()+"");
    };
    ...
    public static void main(String[] args) {
        for (int i=0;i<10;i++){
            new Thread(()->{
                LazyMan.getInstance();
            }).start();
        }
    }

在这里插入图片描述
在这里插入图片描述
可以看到结果都不一样。因此,并发情况下,这段代码是有问题的。
我们需要进行两端检测,进行“加锁”:synchronized (Singleton.class)。

	双重检测锁模式的 懒汉式单例 DCL懒汉式
	public static LazyMan getInstance(){
        if (lazyMan==null){
            synchronized (LazyMan.class){
                if (lazyMan==null){
                    lazyMan = new LazyMan();
                } 
            }
        }
        return lazyMan;
    }

在这里插入图片描述
可以看到结果都是只有一个,按理来说是没有问题。但是结果真的是这样的吗?
在这里插入图片描述
这行代码是存在问题的,这不是一个原子性操作。

静态内部类单例

public class Inner {

    private Inner(){};

    public static Inner getInstance(){
        return InnerClass.INNER;
    }

    public static class InnerClass{
        private static final Inner INNER=new Inner();
    }
}

不管是修改过的懒汉式单例,还是静态内部类单例都是不安全,存在问题的。使用反射的方法可以很轻松的进行破坏。

单例模式优缺点

优点
单例模式可以保证内存里只有一个实例,减少了内存的开销。
可以避免对资源的多重占用。
单例模式设置全局访问点,可以优化和共享资源的访问。
缺点
单例模式一般没有接口,扩展困难。
单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。

工厂方法模式

工厂方法模式的实质

实例化对象不是用new,用工厂方法替代。
将选择实现类,创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。

简单工厂模式

用来生产同一等级架构中的任意产品(对于增加新的产品,需要修改已有代码)
在简单工厂模式中,可以根据参数的不同返回不同类的实例。
简单工厂模式专门定义一个类来负责创建其他类的实例

//创建手机接口
public interface Phone {
    void name();
}

//创建华为实现类
public class HuaWei implements Phone{
    @Override
    public void name() {
        System.out.println("华为手机");
    }
}

//创建小米实现类
public class XiaoMi implements Phone{
    @Override
    public void name() {
        System.out.println("小米手机");
    }
}

//创建工厂
public class PhoneFactory {
    public static Phone getPhone(String phone){
        if (phone.equals("华为")){
            return new HuaWei();
        }else if (phone.equals("小米")){
            return new XiaoMi();
        }else {
            return null;
        }
    }
}

//测试
public class Consumer {
    public static void main(String[] args) {
        //直接创建
//        Phone phone=new HuaWei();
//        Phone phone2=new XiaoMi();

        //使用工厂创建对象
        Phone phone = PhoneFactory.getPhone("华为");
        Phone phone2 = PhoneFactory.getPhone("小米");

        phone.name();
        phone2.name();
    }
}

我们通过创建一个PhoneFactory类,成功的完成工厂的创建。我们在创建对象时,也就不需要直接创建对象,而是可以通过创建工厂,这样大大的降低了代码的耦合性

但是,静态工厂模式是不能添加数据的。比如说,我们想添加一个“Oppo”手机类,你不直接修改PhoneFactory工厂代码,是不能实现的。所以,就有了第二种的工厂方法模式。

工厂方法模式

用来生产同一等级架构中的固定产品,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。(支持增加任意产品)

//创建手机接口
public interface Phone {
    void name();
}

//创建华为实现类
public class HuaWei implements Phone{
    @Override
    public void name() {
        System.out.println("华为手机");
    }
}

//创建手机工厂接口
public interface PhoneFactory {
    Phone getPhone();
}

//创建华为工厂
public class HuaWeiFactory implements PhoneFactory{
    @Override
    public Phone getPhone() {
        return new HuaWei();
    }
}

//测试
public class Consumer {
    public static void main(String[] args) {
        Phone phone = new HuaWeiFactory().getPhone();
        phone.name();
    }
}

我们创建了手机工厂接口PhoneFactory,再创建华为工厂HuaWeiFactory实现工厂,这样就可以通过HuaWeiFactory创建对象。增加新的具体工厂和产品族很方便,比如说,我们想要增加小米,只需要创建一个小米工厂XiaoMiFactory实现手机工厂接口PhoneFactory,合理的解决的简单工厂模式不能修改代码的缺点。

但是,在现实使用中,简单工厂模式占绝大多数。

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

结构的复杂度:简单工厂模式占优。
代码的复杂度:简单工厂模式占优。
编程的复杂度:简单工厂模式占优。
管理的复杂的:简单工厂模式占优。
因此,虽然简单工厂模式不符合设计模式,但是实际使用远大于工厂方法模式

抽象工厂模式

定义

抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类(围绕一个超级工厂创建其他工厂,该超级工厂称为工厂的工厂)

抽象工厂模式的主要角色

1 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
2具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
3抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
4具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

//电脑接口
public interface Computer {
    void play();
    void watch();
}

//创建华为电脑对象
public class HuaWeiComputer implements Computer{
    @Override
    public void play() {
        System.out.println("华为电脑玩游戏");
    }

    @Override
    public void watch() {
        System.out.println("华为电脑看视频");
    }
}

//手机接口
public interface Phone {
    void send();
    void call();
}

//创建华为手机对象
public class HuaWeiPhone implements Phone{
    @Override
    public void send() {
        System.out.println("华为手机发短信");
    }

    @Override
    public void call() {
        System.out.println("华为手机打电话");
    }
}

//抽象工厂
public interface IProductFactory {
    //生产手机
    Phone phone();

    //生产电脑
    Computer computer();
}

//创建华为工厂
public class HuaWeiFactory implements IProductFactory{
    @Override
    public Phone phone() {
        return new HuaWeiPhone();
    }

    @Override
    public Computer computer() {
        return new HuaWeiComputer();
    }
}

//测试
public class Consumer {
    public static void main(String[] args) {
        //华为工厂
        HuaWeiFactory huaWeiFactory=new HuaWeiFactory();

        Phone phone=huaWeiFactory.phone();
        phone.call();
        phone.send();
    }
}

我们通过创建一个抽象工厂完成了对具体工厂的创建,只需要传入参数就可以实例化对象。具体产品在应用层的代码隔离,无需关心创建的细节将一个系列的产品统一到一起创建。将一系列产品规划到一起创建。
但是,抽象工厂模式也存在着缺点。规定了所有可能被创建的产品集合,产品簇中扩展新的产品困难,不可以增加产品,只能增加品牌。

总结

到此,完成了软件设计模式的概述和单例模式、工厂模式和抽象工厂模式三种设计模式的学习总结。之后,还会对其他四种设计模式进行总结。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值