• Gof23-创建型-工厂-单例-抽象工厂-建造-原型以及UML的绘制


    工厂模式

    工厂模式 Factory Pattern

    适用的场景:统一的接口作为统一的零件,实现类作为零件的组合,将实例产品类的生产交给工厂,用户只需要面对工程提取指定的产品。

    比如:客户需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现

    思想创建的过程在子类中实现

    具体实现,创建一个接口,创建多个接口的实现类,重写实现对应的方法,创建一个工厂类,工厂类中实现方法传入类型生产对应的接口实现类,返回接口,编写测试方法,new一个工厂传入多个类型就可以生产对应的产品了。

    在这里插入图片描述

    class CarFactory{
        public Production getProduction(String type){
            if (type == null) return null;
            if (type.equalsIgnoreCase("BaoMa")){
                return new BaoMa();
            } else if (type.equalsIgnoreCase("BiYaDi")) {
                return new BiYaDi();
            } else if (type.equalsIgnoreCase("AoDi")) {
                return new AoDi();
            }
            return null;
        }
    }
    
    class BaoMa implements Production{
    
        @Override
        public void production() {
            System.out.println("宝马车工厂生产中......");
        }
    }
    
    class BiYaDi implements Production{
    
        @Override
        public void production() {
            System.out.println("比亚迪车工厂生产中......");
        }
    }
    
    class AoDi implements Production{
    
        @Override
        public void production() {
            System.out.println("奥迪车工厂生产中......");
        }
    }
    
    interface Production{
        void production();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    测试方法

        public static void main(String[] args) {
            CarFactory carFactory = new CarFactory();
            carFactory.getProduction("baoma").production();
            carFactory.getProduction("aodi").production();
            carFactory.getProduction("biyadi").production();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    单例模式

    单例模式 Singleton Pattern

    适用的场景,保证一个类仅有一个实例,并提供一个访问它的全局访问点。

    例如,一个班级只有一个班主任,window对同一个文件的处理,设备处理器,打印机

    具体实现,一个类有且具有一个实例,并且构造器私有,分为饿汉式单例和懒汉式单例

    在这里插入图片描述

    饿汉式单例

    在类初始化的时就实例化对象,因此它是线程安全的,存在的问题就是使用不当,会造成空间资源的浪费

    class Hungry{
        
        private final static Hungry hungry = new Hungry();
    
        private Hungry() {}
    
        public static Hungry getHungry() {
            return hungry;
        }
    
        public void hello(){
            System.out.println("饿汉式单例的hello()");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    存在问题,如果在Hungry的代码中加入一下代码,那么在类初始化时候,占用了这些空间,但是没有使用,就造成空间资源的浪费。

        byte[] a = new byte[1024*1024];
        byte[] b = new byte[1024*1024];
        byte[] c = new byte[1024*1024];
    
    • 1
    • 2
    • 3

    测试方法,仅能通过类在最开始私有进行实例化对象进行操作方法

        public static void main(String[] args) {
            // 仅仅能通过私有构造器进行对象的初始化工作,并且在最开始就进行了对象的初始化
            Hungry hungry = Hungry.getHungry();
            hungry.hello();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    懒汉式单例

    不安全的基本的懒汉式单例,在get实例方法时候加入判空操作

    class LazyMan{
        private static LazyMan lazyMan;
    
        private LazyMan() {}
    
        public static LazyMan getLazyMan() {
            if (lazyMan == null){
                lazyMan = new LazyMan();
            }
            return lazyMan;
        }
    
        public void hello(){
            System.out.println("饿汉式单例的hello()");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    测试方法

        public static void main(String[] args) {
            LazyMan lazyMan = LazyMan.getLazyMan();
            lazyMan.hello();
        }
    
    • 1
    • 2
    • 3
    • 4

    存在问题懒汉单例,当程序启动之后并不会进行初始化,在什么时候调用什么时候初始化。单线程下没有问题,但是在多线程下,由于没有加锁,所以会存在访问问题。

    思考什么情况会导致线程不安全

    • 线程的调度是抢占式执行
    • 修改操作不是原子的
    • 多个线程同时修改同一个变量
    • 内存可见性
    • 指令重排序

    在并发访问的时候,线程实并发来访问这个懒汉式单例的,多个线程访问的结果不一致

    加锁保证懒汉式单例的安全,直接在方法上进行加锁,但是锁的粒度过大,相对比较笨重

        public static synchronized LazyMan getLazyMan() {
            if (lazyMan == null){
                lazyMan = new LazyMan();
            }
            return lazyMan;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    DCL优化加锁,在方法上双重检查锁,加入voliate关键字,作用是内存可见性,禁止指令重排序

    class LazyMan{
        private volatile static LazyMan lazyMan;
    
        private LazyMan() {}
    
        public static LazyMan getLazyMan() {
            if (lazyMan == null){
                synchronized (LazyMan.class){
                    if (lazyMan == null){
                        lazyMan = new LazyMan();
                    }
                }
            }
            return lazyMan;
        }
    
        public void hello(){
            System.out.println("饿汉式单例的hello()");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    抽象工厂

    抽象工厂 abstract Factory

    使用场景,一个超级工厂去创建其他的小工厂,主要解决接口选择的问题。

    例如,QQ 换皮肤,一整套一起换。 生成不同操作系统的程序。

    在这里插入图片描述

    具体实现

    定义具体实现的两个接口,包含了各自的方法

    interface Shape{
        public void draw();
    }
    
    interface Color{
        public void fill();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    接口实现类,具体实现接口方法

    class Rectangle implements Shape{
        @Override
        public void draw() {
            System.out.println("画出一个长方形");
        }
    }
    
    class Trangle implements Shape{
        @Override
        public void draw() {
            System.out.println("画出一个三角形");
        }
    }
    
    class Circle implements Shape{
        @Override
        public void draw() {
            System.out.println("画出一个圆形");
        }
    }
    
    class Red implements Color{
        @Override
        public void fill() {
            System.out.println("该图形填充了Red");
        }
    }
    
    class Blue implements Color{
        @Override
        public void fill() {
            System.out.println("该图形填充了Blue");
        }
    }
    
    class Green implements Color{
        @Override
        public void fill() {
            System.out.println("该图形填充了Green");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    定义抽象工厂类,每一个具体的工厂类继承这个抽象工厂类,在这个具体的工厂类中实现对应的零件

    abstract class AbstractFactory{
        public abstract Shape getShape(String shape);
        public abstract Color getColor(String color);
    }
    
    class ShapeFactory extends AbstractFactory{
    
        @Override
        public Shape getShape(String shape) {
            if (shape == null) return null;
            if (shape.equalsIgnoreCase("Rectangle")){
                return new Rectangle();
            } else if (shape.equalsIgnoreCase("Trangle")) {
                return new Trangle();
            } else if (shape.equalsIgnoreCase("Circle")) {
                return new Circle();
            }
            return null;
        }
    
        @Override
        public Color getColor(String color) {
            return null;
        }
    }
    
    class ColorFactory extends AbstractFactory{
    
        @Override
        public Shape getShape(String shape) {
            return null;
        }
    
        @Override
        public Color getColor(String color) {
            if (color == null) return null;
            if (color.equalsIgnoreCase("Red")){
                return new Red();
            } else if (color.equalsIgnoreCase("Blue")) {
                return new Blue();
            } else if (color.equalsIgnoreCase("Green")) {
                return new Green();
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    由于这个抽象工厂没有实例,所以需要一个工厂处理器,来处理抽象工厂,让其返回用户需要

    class FactoryProducer{
        public AbstractFactory getFactory(String factory){
            if (factory == null) return null;
            if (factory.equalsIgnoreCase("ShapeFactory")){
                return new ShapeFactory();
            } else if (factory.equalsIgnoreCase("ColorFactory")) {
                return new ColorFactory();
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    测试方法,工厂处理器通过抽象的超级工厂获取工厂的类型,通过指定的工厂就可以对指定的工具类进行操作

        public static void main(String[] args) {
            FactoryProducer factoryProducer = new FactoryProducer();
            AbstractFactory shapeFactory = factoryProducer.getFactory("ShapeFactory");
            shapeFactory.getShape("Rectangle").draw();
            shapeFactory.getShape("Trangle").draw();
            shapeFactory.getShape("Circle").draw();
    
            AbstractFactory colorFactory = factoryProducer.getFactory("ColorFactory");
            colorFactory.getColor("Red").fill();
            colorFactory.getColor("Blue").fill();
            colorFactory.getColor("Green").fill();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    建造者模式

    建造者模式 Builder Pattern

    使用多个简单的对象一步一步构建成一个复杂的对象,建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。

    应用,去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。JAVA 中的 StringBuilder。

    厂模式的区别是:建造者模式更加关注与零件装配的顺序。

    在这里插入图片描述

    具体实现

    创建接口,套餐项的接口,包装接口

    // 套餐项,喝的,吃的
    interface Item{
        public String name();
        public Packing packing();
        public float price();
    }
    // 包装:纸质包装,瓶装
    interface Packing{
        public String pack();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    包装接口的实现类,纸质包装和瓶装

    class Wrapper implements Packing {
    
        @Override
        public String pack() {
            return "Wrapper";
        }
    }
    
    class Bottle implements Packing {
    
        @Override
        public String pack() {
            return "Bottle";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    抽象类封装基本的套餐项,饮料采用瓶子装,汉堡采用纸质装

    // 创建实现 Item 接口的抽象类,该类提供了默认的功能。基本的汉堡,饮料的种类
    abstract class ColdDrink implements Item {
    
        @Override
        public Packing packing() {
            return new Bottle();
        }
    
        @Override
        public abstract float price();
    }
    
    abstract class Burger implements Item {
    
        @Override
        public Packing packing() {
            return new Wrapper();
        }
    
        @Override
        public abstract float price();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    创建扩展了 Burger ColdDrink 的实体类。在汉堡上再封装成为蔬菜汉堡,鸡肉汉堡等,在喝的项目上封装可乐等饮料

    
    class VegBurger extends Burger {
    
        @Override
        public float price() {
            return 25.0f;
        }
    
        @Override
        public String name() {
            return "Veg Burger";
        }
    }
    class ChickenBurger extends Burger {
    
        @Override
        public float price() {
            return 50.5f;
        }
    
        @Override
        public String name() {
            return "Chicken Burger";
        }
    }
    
    class Coke extends ColdDrink {
    
        @Override
        public float price() {
            return 30.0f;
        }
    
        @Override
        public String name() {
            return "Coke";
        }
    }
    class Pepsi extends ColdDrink {
    
        @Override
        public float price() {
            return 35.0f;
        }
    
        @Override
        public String name() {
            return "Pepsi";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    item存入集合,并且计算套餐的价值及其一系列附加属性

    class Meal {
        private List<Item> items = new ArrayList<Item>();
    
        public void addItem(Item item){
            items.add(item);
        }
    
        public float getCost(){
            float cost = 0.0f;
            for (Item item : items) {
                cost += item.price();
            }
            return cost;
        }
    
        public void showItems(){
            for (Item item : items) {
                System.out.print("Item : "+item.name());
                System.out.print(", Packing : "+item.packing().pack());
                System.out.println(", Price : "+item.price());
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    Builder类,负责准备两种不同的套餐,有蔬菜的套餐和没有蔬菜的套餐

    class MealBuilder {
    
        public Meal prepareVegMeal (){
            Meal meal = new Meal();
            meal.addItem(new VegBurger());
            meal.addItem(new Coke());
            return meal;
        }
    
        public Meal prepareNonVegMeal (){
            Meal meal = new Meal();
            meal.addItem(new ChickenBurger());
            meal.addItem(new Pepsi());
            return meal;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    测试方法

        public static void main(String[] args) {
            MealBuilder mealBuilder = new MealBuilder();
    
            Meal vegMeal = mealBuilder.prepareVegMeal();
            System.out.println("Veg Meal");
            vegMeal.showItems();
            System.out.println("Total Cost: " +vegMeal.getCost());
    
            Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
            System.out.println("\n\nNon-Veg Meal");
            nonVegMeal.showItems();
            System.out.println("Total Cost: " +nonVegMeal.getCost());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    原型模式

    利用已有的一个原型对象,快速地生成和原型对象一样的实例。通常用于克隆,可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

    优点 性能提高。 逃避构造函数的约束。

    应用 细胞分裂。JAVA 中的 Object clone() 方法。

    在这里插入图片描述

    具体实现

    定义一个含有抽象方法的抽象类,实现克隆的接口

    abstract class Shape implements Cloneable {
    
        private String id;
        protected String type;
    
        abstract void draw();
    
        public String getType(){
            return type;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public Object clone() {
            Object clone = null;
            try {
                clone = super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return clone;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    给抽象类进行扩展

    class Rectangle extends Shape {
     
       public Rectangle(){
         type = "Rectangle";
       }
     
       @Override
       public void draw() {
          System.out.println("Inside Rectangle::draw() method.");
       }
    }
    
    class Square extends Shape {
     
       public Square(){
         type = "Square";
       }
     
       @Override
       public void draw() {
          System.out.println("Inside Square::draw() method.");
       }
    }
    
    class Circle extends Shape {
     
       public Circle(){
         type = "Circle";
       }
     
       @Override
       public void draw() {
          System.out.println("Inside Circle::draw() method.");
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    Shape 的缓存类,负责先一步加载缓存

    class ShapeCache {
    
        private static Hashtable<String, Shape> shapeMap
                = new Hashtable<String, Shape>();
    
        public static Shape getShape(String shapeId) {
            Shape cachedShape = shapeMap.get(shapeId);
            return (Shape) cachedShape.clone();
        }
        
        public static void loadCache() {
            Circle circle = new Circle();
            circle.setId("1");
            shapeMap.put(circle.getId(),circle);
    
            Square square = new Square();
            square.setId("2");
            shapeMap.put(square.getId(),square);
    
            Rectangle rectangle = new Rectangle();
            rectangle.setId("3");
            shapeMap.put(rectangle.getId(),rectangle);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    测试方法

    public static void main(String[] args) {
          ShapeCache.loadCache();
     
          Shape clonedShape = (Shape) ShapeCache.getShape("1");
          System.out.println("Shape : " + clonedShape.getType());        
     
          Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
          System.out.println("Shape : " + clonedShape2.getType());        
     
          Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
          System.out.println("Shape : " + clonedShape3.getType());        
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    UML图形的绘制

    UML与代码基本元素的对应关系

    interface class之间的关系与对象与对象之间的关系

    泛化关系也就是继承关系

    在这里插入图片描述
    -表示 private

    + 表示 public

    #表示protected

    不带符号代表 default

    UML表示具体类
    在这里插入图片描述

    UML 表示抽象类,抽象类的类名以及抽象方法的名字都用斜体字表示

    在这里插入图片描述

    接口

    在这里插入图片描述
    或者(棒棒糖表示法)
    在这里插入图片描述

    UML 表示包

    在这里插入图片描述

    UML表示类、接口、对象的关系

    实现关系implements,一个类实现了一个接口

    在这里插入图片描述

    泛化关系extends,也就是类之间的继承关系

    is a 关系表示

    在这里插入图片描述

    关联关系 Association

    代码表现形式为一个对象含有另一个对象的引用

    关联关系有单向关联和双向关联。如果两个对象都知道(即可以调用)对方的公共属性和操作,那么二者就是双向关联。如果只有一个对象知道(即可以调用)另一个对象的公共属性和操作,那么就是单向关联。大多数关联都是单向关联,单向关联关系更容易建立和维护,有助于寻找可重用的类。

    在这里插入图片描述

    关联关系又分为依赖关联、聚合关联和组合关联三种类型

    依赖关系 Dependency

    属于一种弱关联关系,使用 use a

    依赖关系在Java中的具体代码表现形式为B为A的构造器或方法中的局部变量、方法或构造器的参数、方法的返回值,或者A调用B的静态方法。

    在这里插入图片描述
    聚合关系 Aggregation

    体现的是整体与部分的拥有关系使用 has a,是一种弱引用关系

    此时整体与部分之间是可分离的,它们可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享,所以聚合关系也常称为共享关系。

    例如,公司部门与员工的关系,一个员工可以属于多个部门,一个部门撤消了,员工可以转到其它部门。

    在这里插入图片描述

    组合关系 Composition也是关联关系的一种特例,它同样体现整体与部分间的包含关系,即 “contains a” 的关系。强关联关系

    例如,人包含头、躯干、四肢,它们的生命周期一致。当人出生时,头、躯干、四肢同时诞生。当人死亡时,作为人体组成部分的头、躯干、四肢同时死亡。

    在这里插入图片描述

    参考链接

    https://zhuanlan.zhihu.com/p/109655171

    https://www.runoob.com/design-pattern/factory-pattern.html

  • 相关阅读:
    【寻找链表的中间结点】python实现-附ChatGPT解析
    06-网络程序设计
    Linux之FinalShell的安装和使用
    LeetCode每日一题(468. Validate IP Address)
    Netty 4.1.98.Final 发布
    Ubuntu安装中文拼音输入法
    面试时必问的五大问题
    IEC61499的理解及相关应用
    Log4j2
    UniApp组件封装
  • 原文地址:https://blog.csdn.net/qq_46724069/article/details/128026461