设计模式:单例模式—工厂模式—原型模式

设计模式类别:

在这里插入图片描述

设计模式遵循的原则:

设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经 验的总结。 使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设 计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

总原则:开闭原则

开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的 代码,而是要扩展原有代码,实现一个热插拔的效果。
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
这样的设计,能够面对需求改变却可以保持相对稳定,从而使系统在第一个版本以后不断推 出新的版本;面对需求,对程序的改动是通过增加新的代码进行的,而不是更改现有的代码; 所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我 们需要使用接口和抽象类等

1、单一职责原则

定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。 问题由来:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修 改类T时,有可能会导致原本运行正常的职责P2功能发生故障。
解决方案:遵循单一职责原则。分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职 责P2功能。这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使 职责P1发生故障风险。

2、里氏替换原则

里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地 方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功 能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代 换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的 继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
里氏替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构, 通过这个规范的接口与外界交互,子类不应该随便破坏它。

3、依赖倒置原则

定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节 应该依赖抽象。
问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达 成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本 的原子操作;假如修改类A,会给程序带来不必要的风险。
解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者 类C发生联系,则会大大降低修改类A的几率。

4、接口隔离原则

这个原则的意思是:每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接 口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。
接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是 如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度

5、迪米特法则(最少知道原则)

高内聚(类内部的定义尽量紧密)低耦合(类跟类之间的尽量不要有依赖)
就是说:一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应 该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小
的影响该类。
最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋 友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值 中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变 量出现在类中。

6、合成复用原则

尽量使用合成/聚合.避免继承.在新类中应该尽量使用关联关系采用现有的对象,使之成为新对 象的一部分.达到现有功能复用的目的.
通过合成聚合的原则可以降低类于类之间的依赖关系.被依赖的类的修改对其他类的影响相对 小一些.
合成/聚合原则是动态的.可以自由选择使用现有类的那些方法.而继承是静态的,失去了灵活性. 如果父类改变有可能会影响子类的修改,同时破坏了父类的封装性,父类将会暴露不相关的方法给 子类.

单例模式

单例模式(Singleton Pattern)
类型:创建性模式
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。 这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 主要解决:一个全局使用的类频繁地创建与销毁。
使用场景:在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序 对象常被设计成单例。
单例模式的三要素:
Ø 私有的构造方法;
Ø 指向自己实例的私有静态引用;—私有的静态成员变量:数据类型是自己
Ø 以自己实例为返回值的静态的公有方法。----

单例模式根据实例化对象时机的不同,有两种经典的实现: 一种是 饿汉式单例(立即加载),一种是 懒汉式单例(延迟加载)。
在这里插入图片描述

饿汉式单例—代码:

God :

package com.aaa.test1;

/**
 * 单例模式:饿汉模式。加同步锁:优点:即实现了懒加载,又保证了线程安全;
 */
public class God {
    //定义当前类的静态对象
    private static God god = new God();

    //设置私有构造
    private God(){
        System.out.println("调用了God private构造");
    }

    //对外提供返回对象的方法
    public static God getInstance(){
        return God.god;
    }

    //上帝创造世界
    public void createWorld(){
        System.out.println("上帝创造世界...");
    }
}

Test1 :

package com.aaa.test1;

public class Test1 {
    public static void main(String[] args) {
        God g1 = God.getInstance();
        God g2 = God.getInstance();
        System.out.println(g1);
        System.out.println(g2);
    }
}

运行结果:

在这里插入图片描述

在这里插入图片描述

懒汉式单例—代码:

God :

package com.aaa.test2;

public class God {
    private static Object obj = new Object();
    //懒汉模式:声明变量,不直接创建
    private static God god;
    //构造私有
    private God(){}

    //根据需要创建对象
    public static God getInstance(){
        //如果对象为空,则创建,否则直接返回。这种方式,多线程并发时会出问题
        if(god==null){
            //同步锁,双检double check
            synchronized (obj) {
                if(god==null) {
                    god = new God();
                }
            }
        }
        return god;
    }

    public void createWold(){
        System.out.println("上帝创建世界....");
    }
}

Test :

package com.aaa.test2;

public class Test {
    public static void main(String[] args) {
//        God g1 = God.getInstance();
//        God g2 = God.getInstance();
//        System.out.println(g1);
//        System.out.println(g2);
        for (int i=1;i<=100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    God god = God.getInstance();
                    System.out.println(god);
                }
            }).start();
        }
    }
}

运行结果:

在这里插入图片描述

懒汉模式:静态内部类实现。保证线程安全—代码:

God :

package com.aaa.test3;

/**
 * 懒汉模式:静态内部类实现。保证线程安全
 */
public class God {
    private God(){
        System.out.println("调用了God的private构造");
    }

    //静态内部类
    static class InnerCls{
        //内部类种定义静态对象
        static God god = new God();
    }

    //获取静态内部类种的对象
    public static God getInstance(){
        return InnerCls.god;
    }
}

Test :

package com.aaa.test3;

public class Test {
    public static void main(String[] args) {
        God g1=God.getInstance();
        God g2=God.getInstance();
        System.out.println(g1);
        System.out.println(g2);
    }
}

运行结果:

在这里插入图片描述

工厂模式

简单工厂(普通工厂)—代码:

ICar :

package com.aaa.test4;

/**
 * 定义商品接口:车
 */
public interface ICar {
    void run();
}

MiniCar :

package com.aaa.test4;

public class MiniCar implements ICar{
    @Override
    public void run() {
        System.out.println("mini车在跑...");
    }
}

SUVCar :

package com.aaa.test4;

public class SUVCar implements ICar{
    @Override
    public void run() {
        System.out.println("SUV车在跑...");
    }
}

WuLing :

package com.aaa.test4;

public class WuLing implements ICar{
    @Override
    public void run() {
        System.out.println("五菱之光在跑...");
    }
}

CarFactory :

package com.aaa.test4;

/**
 * 商品对象工厂:创建各种类型的车
 */
public class CarFactory {
    /**
     * 根据车的类型来创建
     * @param carType
     * @return
     */
    public static ICar getInstance(String carType){
        switch (carType){
            case "mini":
                return new MiniCar();
            case "suv":
                return new SUVCar();
            case "wl":
                return new WuLing();
        }
        return null;
    }
}

Test :

package com.aaa.test4;

public class Test {
    public static void main(String[] args) {
        //对象的创建在工厂中完成,对使用者隐藏细节。
        //使用者根据需要调用工厂方法获取对象
        //好处:当对象的创建发生变化时,对使用影响很小
        ICar c1 = CarFactory.getInstance("mini");
        c1.run();

        ICar c2 = CarFactory.getInstance("suv");
        c2.run();

        ICar c3 = CarFactory.getInstance("wl");
        c3.run();
    }
}

运行结果:

在这里插入图片描述

多个工厂方法模式—代码:

ICar :

package com.aaa.test4;

/**
 * 定义商品接口:车
 */
public interface ICar {
    void run();
}

MiniCar :

package com.aaa.test4;

public class MiniCar implements ICar{
    @Override
    public void run() {
        System.out.println("mini车在跑...");
    }
}

SUVCar :

package com.aaa.test4;

public class SUVCar implements ICar{
    @Override
    public void run() {
        System.out.println("SUV车在跑...");
    }
}

WuLing :

package com.aaa.test4;

public class WuLing implements ICar{
    @Override
    public void run() {
        System.out.println("五菱之光在跑...");
    }
}

CarFactory :

package com.aaa.test4;

/**
 * 商品对象工厂:创建各种类型的车
 */
public class CarFactory {
    /**
     * 根据车的类型来创建
     * @param carType
     * @return
     */
    public static ICar getInstance(String carType){
        switch (carType){
            case "mini":
                return new MiniCar();
            case "suv":
                return new SUVCar();
            case "wl":
                return new WuLing();
        }
        return null;
    }
}

Test :

package com.aaa.test5;

public class Test {
    public static void main(String[] args) {
        //对象的创建在工厂中完成,对使用者隐藏细节。
        //使用者根据需要调用工厂方法获取对象
        //好处:当对象的创建发生变化时,对使用影响很小
        ICar c1 = CarFactory.getMiniCar();
        ICar c2 = CarFactory.getSUVCar();
        ICar c3 = CarFactory.getWLCar();

        c1.run();
        c2.run();
        c3.run();
    }
}

运行结果:

在这里插入图片描述

静态工厂模式—代码(略)

抽象工厂模式—代码:

IFactory :

package com.aaa.test6;

/**
 * 抽象工厂
 */
public interface IFactory {
    //手机
    IPhone createPhone();
    //Tv
    ITv createTv();
}

IPhone :

package com.aaa.test6;

public interface IPhone {
    void call();
}

ITv :

package com.aaa.test6;

public interface ITv {
    void show();
}

HuaWeiFactory :

package com.aaa.test6;

public class HuaWeiFactory implements IFactory{
    @Override
    public IPhone createPhone() {
        return new HuaWeiPhone();
    }

    @Override
    public ITv createTv() {
        return new HuaWeiTv();
    }
}

HuaWeiPhone :

package com.aaa.test6;

public class HuaWeiPhone implements IPhone{
    @Override
    public void call() {
        System.out.println("使用华为手机打电话");
    }
}

HuaWeiTv :

package com.aaa.test6;

public class HuaWeiTv implements ITv{
    @Override
    public void show() {
        System.out.println("使用华为电视看大片。。。");
    }
}

XiaoMiFactory :

package com.aaa.test6;

public class XiaoMiFactory implements IFactory{
    @Override
    public IPhone createPhone() {
        return new XiaoMiPhone();
    }

    @Override
    public ITv createTv() {
        return new XiaoMiTv();
    }
}

XiaoMiPhone :

package com.aaa.test6;

public class XiaoMiPhone implements IPhone{
    @Override
    public void call() {
        System.out.println("使用小米手机打电话...");
    }
}

XiaoMiTv :

package com.aaa.test6;

public class XiaoMiTv implements ITv{
    @Override
    public void show() {
        System.out.println("使用小米电视看大片...");
    }
}

Test :

package com.aaa.test6;

public class Test {
    public static void main(String[] args) {
        //创建华为工厂,获取华为产品
        IFactory f1 = new HuaWeiFactory();
        IPhone p1 =f1.createPhone();
        ITv t1 = f1.createTv();
        p1.call();
        t1.show();

        IFactory f2 = new XiaoMiFactory();
        IPhone p2 = f2.createPhone();
        ITv t2 = f2.createTv();
        p2.call();
        t2.show();
    }
}

运行结果:

在这里插入图片描述

原型模式—代码:

Dog :

package com.aaa.test7;

public class Dog {
    //名字
    private String name;
    //颜色
    private String color;
    //年龄
    private int age;
    //朋友
    private Dog friend;

    public Dog() {
    }

    public Dog(String name, String color, int age) {
        this.name = name;
        this.color = color;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Dog getFriend() {
        return friend;
    }

    public void setFriend(Dog friend) {
        this.friend = friend;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", age=" + age +
                ", friend=" + friend +
                '}';
    }
}

Test :

package com.aaa.test7;

public class Test {
    public static void main(String[] args) {
        //原型对象
        Dog d1_fiend=new Dog("小白","白色",1);
        Dog d1=new Dog("旺财","黄色",2);
        d1.setFriend(d1_fiend);

        //想要复制一个新狗。这种方式,并没有实际创建新的狗对象。两个变量指向的是同一个狗对象。
        //所以根本上,没有实现对象复制效果
        Dog d2 = d1;

        System.out.println(d1.hashCode());
        System.out.println(d2.hashCode());
        //System.out.println(d1);
        //System.out.println(d2);

        System.out.println("===============");
        d1.setName("旺旺财");
        System.out.println(d1);
        System.out.println(d2);

    }
}

运行结果:

在这里插入图片描述

原型模式:浅拷贝:要真正实现复制效果(克隆),要实现Cloneable和序列化接口—代码:

Dog :

package com.aaa.test8;

import java.io.Serializable;

/**
 * 原型模式:要真正实现复制效果(克隆),要实现Cloneable和序列化接口
 */
public class Dog implements Cloneable, Serializable {
    //名字
    private String name;
    //颜色
    private String color;
    //年龄
    private int age;
    //朋友
    private Dog friend;

    public Dog() {
    }

    public Dog(String name, String color, int age) {
        this.name = name;
        this.color = color;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Dog getFriend() {
        return friend;
    }

    public void setFriend(Dog friend) {
        this.friend = friend;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", age=" + age +
                ", friend=" + friend +
                '}';
    }

    /**
     * 实现克隆接口方法,克隆一个单独的对象。但是此方法的克隆是浅copy模式
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

Test :

package com.aaa.test8;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        //原型对象
        Dog d1_fiend=new Dog("小白","白色",1);
        Dog d1=new Dog("旺财","黄色",2);
        d1.setFriend(d1_fiend);

        //通过克隆方法实现对象复制,通过测试发现,是两个具有相同属性值的独立对象
        //但是这种方式实现的浅copy(只复制了对象的简单属性,对于嵌套的对象属性,并没有实现独立的克隆)
        Dog d2 = (Dog) d1.clone();

        System.out.println(d1.hashCode());
        System.out.println(d2.hashCode());
        System.out.println(d1);
        System.out.println(d2);

        System.out.println("=====================");
        d1.setName("旺旺财");
        d1.getFriend().setName("小小白"); //修改狗的朋友的信息
        System.out.println(d1);
        System.out.println(d2);
    }
}

运行结果:

在这里插入图片描述

原型模式:深拷贝:要真正实现复制效果(克隆),要实现Cloneable和序列化接口—代码:

Dog :

package com.aaa.test9;

import java.io.Serializable;

/**
 * 原型模式:要真正实现复制效果(克隆),要实现Cloneable和序列化接口
 */
public class Dog implements Cloneable, Serializable {
    //名字
    private String name;
    //颜色
    private String color;
    //年龄
    private int age;
    //朋友
    private Dog friend;

    public Dog() {
    }

    public Dog(String name, String color, int age) {
        this.name = name;
        this.color = color;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Dog getFriend() {
        return friend;
    }

    public void setFriend(Dog friend) {
        this.friend = friend;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                ", age=" + age +
                ", friend=" + friend +
                '}';
    }

    /**
     * 实现克隆接口方法,克隆一个单独的对象。但是此方法的克隆是浅copy模式
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

CopyUtil :

package com.aaa.test9;

import java.io.*;

public class CopyUtil {
    public static Object deepCopy(Object obj) throws IOException, ClassNotFoundException {
        //定义内存字节输出流:将字节数组输出到内存的某个区域
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        //对象输出字节流:目的是将对象数据,写入到内存字节数组流中
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        //写对象数据
        oos.writeObject(obj);

        //创建字节数组输入流,从上面的字节数组输出流中读取字节数据
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();

    }
}

Test :

package com.aaa.test9;

import java.io.IOException;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        //原型对象
        Dog d1_fiend=new Dog("小白","白色",1);
        Dog d1=new Dog("旺财","黄色",2);
        d1.setFriend(d1_fiend);

        //通过字节数组流的方式,将对象数据写到内存中,然后再复制一份。实现深度copy
        Dog d2 = (Dog)CopyUtil.deepCopy(d1);

        System.out.println(d1.hashCode());
        System.out.println(d2.hashCode());
        System.out.println(d1);
        System.out.println(d2);

        System.out.println("=====================");
        d1.setName("旺旺财");
        d1.getFriend().setName("小小白"); //修改狗的朋友的信息
        System.out.println(d1);
        System.out.println(d2);
    }
}

运行结果:

在这里插入图片描述

注意:

浅拷贝:只能实现值的复制则是浅拷贝;
深度拷贝:能实现嵌套对象的拷贝。
在这里插入图片描述

// A code block
var foo = 'bar';

// A code block
var foo = 'bar';

// A code block
var foo = 'bar';

// A code block
var foo = 'bar';

// A code block
var foo = 'bar';
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值