学习设计模式(二):创建型设计模式

一、单例模式

1.适用场景

项目只需要1个该对象

2.优点和缺点

& 优点:

(1)减少内存开支,对于频繁使用的对象,一直创建销毁,很占用内存
(2)减少性能开销,当一个对象的产生需要比较多的资源,产生一个对象很耗时

&缺点:

(1)无法被继承,因为构造方法是私有的
(2)在并行开发中,如果采用单例模式的类没有完成,是不可以自测的

Get到的:
(1)单元测试时经常会采用stub和mock方式

二、工厂方法模式

工厂方法模式包括四个角色类:抽象工厂类,具体工厂类,抽象产品类,具体产品类

1.使用场景

有一个产品类别,需要在一段代码中频繁修改创建具体产品的代码,这时候可以使用工厂模式,针对每一个具体产品实现一个具体工厂类。
注意:
• 在所有new对象的地方都可以使用,但是要考虑使用工厂类进行管理,是否会增加代码的复杂度
• 工厂方法模式可以用在异构项目中

2.举例代码:

UML类图如下:
在这里插入图片描述

具体代码如下

package com.kk.factoryTest;
public interface Creator {
    /**
     * 创建产品的抽象工厂类
     */
     <T extends Product> T create(Class<T> c);
}
package com.kk.factoryTest;
public class ConcreteCreator implements Creator{
    @Override
    public <T extends Product> T create(Class<T> c) {
        Product product = null;
        // 这里使用泛型也是可以的
        T product1 = null;
        try {
            // 使用Class.forName(String className),返回值是Class<?> 不清楚返回的类型,接着创建该类对应的实例
            // newInstance()返回的是Object,这里是Object转为Product,或者不转也是可以的
            product = (Product) Class.forName(c.getName()).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T) product;
    }
}
package com.kk.factoryTest;
public interface Product {
    void method1();
}
package com.kk.factoryTest;
public class ConcreteProduct implements Product{
    @Override
    public void method1() {
        System.out.println("im concrete product");
    }
}

3.工厂模式,方便扩展具体的工厂类,减少耦合。

三、抽象工厂模式

1. 使用场景

(1) 抽象工厂模式适合有有多种业务类型、多种业务产品的情况,举例:
一个软件需要在三种不同的操作系统上跑,那它得符合每个操作系统的配置,所以在每个操作系统中有一个对应的软件类别,所以在抽象工厂中

public interface SoftwareCreateFactoryInteface {
    SoftwareWindow createInWindow();
    SoftwareMac createInMac();
    SoftwareAndroid createInAndroid(); 
}

(2)抽象工厂模式针对的一族产品,如果产品族中只有一类产品,则抽象方法模式就退化为工厂方法模式,负责就是抽象工厂模式。

2.优点和缺点

&优点

产品族内,不同产品类的依赖关系可以封装在里面。

&缺点

产品族本身的扩展非常难,如果新增加一个产品类,那么必须修改抽象工厂类并且影响到已有的工厂类。

3.举例代码

(1)代码类图
在这里插入图片描述

(2)Get到的知识点:
• 父类的方法,子类是不可以继承的,所以你可以将公有方法设置在父类中,子类中实现这个方法,子类赋值给父类,父类调用这个方法,也是调用的是子类的方法
• UML中六个箭头的含义:https://blog.csdn.net/qq_20936333/article/details/86773664

四、建造者模式

1.含义

(1)将一个复杂对象的创建与表示分离,使得同样的构建过程有不同的表示。
(2)
• 抽象建造者定义产品类的不同组成
• 导演类定义不同组成的装配顺序,组合产生不同的对象

2.使用场景

第一种:相同的方法,不同的执行顺序,产生不同的结果的时候,可以使用建造者模式
第二种:多个部件或者零件,都可以装配到一个对象中;
第二种:产品类非常复杂,使用抽象建造者定义该产品类的不同组成;
建造者关注的是零件类型和装配工艺顺序

3.优点和缺点

&优点

• 封装性,使得客户端不知道产品内部的组成细节
• 便于扩展,可以添加更多的零件,组成不同的产品
• 便于控制细节风险

4.举例代码

(1)UML类图
在这里插入图片描述

(2)各个部分的代码

Computer.java
package com.kk.constructorDesign;
public abstract class Computer {
    private String type; // 类型
    private String cpu; // cpu
    private String ram; // 内存
    private String hardDisk; // 硬盘
    private String monitor; // 显示器
    public String getMonitor() {
        return monitor;
    }
    public void setMonitor(String monitor) {
        this.monitor = monitor;
    }
    private String os; // 操作系统
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getCpu() {
        return cpu;
    }
    public void setCpu(String cpu) {
        this.cpu = cpu;
    }
    public String getRam() {
        return ram;
    }
    public void setRam(String ram) {
        this.ram = ram;
    }
    public String getHardDisk() {
        return hardDisk;
    }
    public void setHardDisk(String hardDisk) {
        this.hardDisk = hardDisk;
    }
    public String getOs() {
        return os;
    }
    public void setOs(String os) {
        this.os = os;
    }
}

T410类

package com.kk.constructorDesign;
/**
 * T401子类
 */
public class T401 extends Computer{
    private String graphicCard;
    public T401() {
        // 子类继承了父类所有的方法
        this.setType("ThinkPad T401");
    }
    public String getGraphicCard() {
        return graphicCard;
    }
    public void setGraphicCard(String graphicCard) {
        this.graphicCard = graphicCard;
    }
    @Override
    public String toString() {
        return "型号:\t" + this.getType() + "\ncpu:\t" +
                this.getCpu() + "\n内存:\t" + this.getRam() +
                "\n硬盘:\t" + this.getHardDisk() + "\n显卡:\t" +
                this.getGraphicCard() + "\n显示器:\t" + this.getMonitor() +
                "\n操作系统:\t" + this.getOs();
    }
}

X201类

package com.kk.constructorDesign;
public class X201 extends Computer {
    public X201() {
        this.setType("ThinkPad X201");
    }
    @Override
    public String toString() {
        return "型号:\t" + this.getType() + "\ncpu:\t" +
                this.getCpu() + "\n内存:\t" + this.getRam() +
                "\n硬盘:\t" + this.getHardDisk()  +
                "\n显示器:\t" + this.getMonitor() +
                "\n操作系统:\t" + this.getOs();
    }
}
ComputerBuilder.class
package com.kk.constructorDesign;
public interface ComputerBuiler {
    void buildCpu();
    void buildRam();
    void buildHardDisk();
    void buildGraphicDisk();
    void buildMonitor();
    void buildOs();
    /**
     * 获得最终生产的计算机
     * @return
     */
    Computer getResult();
}

X201Builer.class

package com.kk.constructorDesign;
public class X201Builder implements ComputerBuiler {
    private X201 computer = new X201();
    @Override
    public void buildCpu() {
        computer.setCpu("i3-350");
    }
    @Override
    public void buildRam() {
        computer.setRam("2GB 1333MHz");
    }
    @Override
    public void buildHardDisk() {
        computer.setHardDisk("250GB 5400转");
    }
    @Override
    public void buildGraphicDisk() {
       //无显卡
    }
    @Override
    public void buildMonitor() {
        computer.setMonitor("12英寸 1280*800");
    }
    @Override
    public void buildOs() {
        computer.setOs("Windows7 Home版");
    }
    @Override
    public Computer getResult() {
        return computer;
    }
}

T401Builder.class

package com.kk.constructorDesign;
public class T401Builder implements ComputerBuiler {
    private  T401 computer = new T401();
    @Override
    public void buildCpu() {
        computer.setCpu("i5-450");
    }
    @Override
    public void buildRam() {
        computer.setRam("4GB 1333MHz");
    }
    @Override
    public void buildHardDisk() {
        computer.setHardDisk("500GB 7200转");
    }
    @Override
    public void buildGraphicDisk() {
        computer.setGraphicCard("Nvidia NVS 3100M");
    }
    @Override
    public void buildMonitor() {
        computer.setMonitor("14英寸 1280*800");
    }
    @Override
    public void buildOs() {
        computer.setOs("Windows 7 旗舰版");
    }
    @Override
    public Computer getResult() {
        return computer;
    }
}

Director.class

package com.kk.constructorDesign;
/**
 * 导演类安排创建计算机的顺序
 */
public class Director {
    private ComputerBuiler builer;
    public Computer buildT401() {
        builer = new T401Builder();
        builer.buildCpu();
        builer.buildRam();
        builer.buildHardDisk();
        builer.buildGraphicDisk();
        builer.buildOs();
        builer.buildMonitor();
        return builer.getResult();
    }
    
    public Computer buildX201() {
        builer = new X201Builder();
        builer.buildCpu();
        builer.buildRam();
        builer.buildHardDisk();
        builer.buildOs();
        builer.buildMonitor();
        return builer.getResult();
    }
}

ComputerDirector.java

package com.kk.constructorDesign;
public class ComputerDirectorTest {
    public static void main(String[] args) {
        Director director = new Director();
        Computer t401 = director.buildT401();
        System.out.println(t401);
        Computer x201 = director.buildX201();
        System.out.println(x201);
    }
}

最终展示的结果
在这里插入图片描述

5.和工厂模式的区别

他们的处理方式不同,工厂模式是具体工厂类决定怎么创建对应的产品
建造者模式是具体建造类实现规定的行为,由导演类决定怎么创建对应的产品

6.Get知识点

1.Java中子类能不能继承父类的私有变量和方法?
分析内存后,会发现,当一个子类被实例化的时候,默认会先调用父类的构造方法对父类进行初始化,即在内存中创建一个父类对象,然后再父类对象的外部放上子类独有的属性,两者合起来成为一个子类的对象。
所以:子类继承了父类的所有属性和方法或子类拥有父类的所有属性和方法是对的,只不过父类的私有属性和方法,子类是无法直接访到的。即只是拥有,但是无法使用。 (这里不考虑Java反射机制)

五、原型模式

1.优点与缺点

&优点

(1)它直接复制的是内存二进制流,当需要大量对象的时候,使用这种方法比new对象好(因为是直接对内存数据复制,速度会更快);
(2)逃避构造函数的约束,不会执行构造函数

2.举例代码

Prototype.class
package com.kk.prototypeDesign;
/**
 * 标记这个接口可以进行克隆
 */
public interface Prototype extends Cloneable{
    Prototype clone();
}
ConcretePrototype.class
package com.kk.prototypeDesign;
/**
 * 子类也可以进行clone
 */
public class ConcretePrototype implements Prototype{
    @Override
    public Prototype clone() {
        try {
            // 这里调用的是Object.clone()方法
           return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}
客户端 Client.java
package com.kk.prototypeDesign;
/**
 * 客户类的要求是为了获得克隆对象
 */
public class Client {
    public void operation(Prototype prototype) {
        Prototype cloneObject = prototype.clone();
    }
}

3.使用场景

(1)资源进行优化,当类初始化非常消耗资源时,这个资源包括数据、硬件资源;
(2)性能和安全要求的场景,通过new产生一个对象需要非常繁琐的数据准备或者访问权限
(3)一个对象很多个修改者的场景。
原型模式一般和工厂模式一起出现,通过clone方法创建一个对象,然后由工厂方法提供给调用者。

4.Get到的知识点

(1)Cloneable接口中没有任何方法,为什么要实现这个接口,并且实现了它后,可以调用Object.clone()方法
& 标明该类可以用于clone,所以要实现Cloneable接口,没有这个标记的话,不允许clone
&要有JVM的支持,所以要调用Oject.clone()或者写成Super.clone()
(2)Object提供的clone方法是浅拷贝,只拷贝对象的引用,而不复制克隆对象的数据,如果要深拷贝,则需要在覆盖克隆方法时,手动控制克隆的深度。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值