创建型设计模式 单例 工厂模式 看这一篇就够了_软工菜鸡的博客-CSDN博客
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
原型模式包含如下角色:
接口类图如下:

原型模式的克隆分为浅克隆和深克隆。
浅克隆:创建一个新对象, 新对象的属性和原来对象完全相同,对于非基本类型属性, 仍指向原有属性 所指向的对象 的 内存 地址。
深克隆:创建一个新对象, 属性中引用的其他对象也会被克隆,不再指向原有对象地址。
Java中的Object类中提供了 clone() 方法来实现浅克隆。 Cloneable 接口是上面的类图中的抽象原型类,而实现了Cloneable接口的子实现类就是具体的原型类。代码如下:
Realizetype(具体的原型类):
- public class Realizetype implements Cloneable {
-
- public Realizetype() {
- System.out.println("具体的原型对象创建完成!");
- }
-
- @Override
- protected Realizetype clone() throws CloneNotSupportedException {
- System.out.println("具体原型复制成功!");
- return (Realizetype) super.clone();
- }
- }
PrototypeTest(测试访问类):
- public class PrototypeTest {
- public static void main(String[] args) throws CloneNotSupportedException {
- Realizetype r1 = new Realizetype();
- Realizetype r2 = r1.clone();
-
- System.out.println("对象r1和r2是同一个对象?" + (r1 == r2));
- }
- }
用原型模式生成“三好学生”奖状
同一学校的“三好学生”奖状除了获奖人姓名不同,其他都相同,可以使用原型模式复制多个“三好学生”奖状出来,然后在修改奖状上的名字即可。
类图如下:

代码如下:
- //奖状类
- public class Citation implements Cloneable {
- private String name;
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getName() {
- return (this.name);
- }
-
- public void show() {
- System.out.println(name + "同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!");
- }
-
- @Override
- public Citation clone() throws CloneNotSupportedException {
- return (Citation) super.clone();
- }
- }
-
- //测试访问类
- public class CitationTest {
- public static void main(String[] args) throws CloneNotSupportedException {
- Citation c1 = new Citation();
- c1.setName("张三");
-
- //复制奖状
- Citation c2 = c1.clone();
- //将奖状的名字修改李四
- c2.setName("李四");
-
- c1.show();
- c2.show();
- }
- }
将上面的“三好学生”奖状的案例中Citation类的name属性修改为Student类型的属性。代码如下:
- //奖状类
- public class Citation implements Cloneable {
- private Student stu;
-
- public Student getStu() {
- return stu;
- }
-
- public void setStu(Student stu) {
- this.stu = stu;
- }
-
- void show() {
- System.out.println(stu.getName() + "同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!");
- }
-
- @Override
- public Citation clone() throws CloneNotSupportedException {
- return (Citation) super.clone();
- }
- }
-
- //学生类
- public class Student {
- private String name;
- private String address;
-
- public Student(String name, String address) {
- this.name = name;
- this.address = address;
- }
-
- public Student() {
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getAddress() {
- return address;
- }
-
- public void setAddress(String address) {
- this.address = address;
- }
- }
-
- //测试类
- public class CitationTest {
- public static void main(String[] args) throws CloneNotSupportedException {
-
- Citation c1 = new Citation();
- Student stu = new Student("张三", "西安");
- c1.setStu(stu);
-
- //复制奖状
- Citation c2 = c1.clone();
- //获取c2奖状所属学生对象
- Student stu1 = c2.getStu();
- stu1.setName("李四");
-
- //判断stu对象和stu1对象是否是同一个对象
- System.out.println("stu和stu1是同一个对象?" + (stu == stu1));
-
- c1.show();
- c2.show();
- }
- }
运行结果为:

说明:
stu对象和stu1对象是同一个对象,就会产生将stu1对象中name属性值改为“李四”,两个Citation(奖状)对象中显示的都是李四。这就是浅克隆的效果,对具体原型类(Citation)中的引用类型的属性进行引用的复制。这种情况需要使用深克隆,而进行深克隆需要使用对象流。代码如下:
- public class CitationTest1 {
- public static void main(String[] args) throws Exception {
- Citation c1 = new Citation();
- Student stu = new Student("张三", "西安");
- c1.setStu(stu);
-
- //创建对象输出流对象
- ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Think\\Desktop\\b.txt"));
- //将c1对象写出到文件中
- oos.writeObject(c1);
- oos.close();
-
- //创建对象出入流对象
- ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Think\\Desktop\\b.txt"));
- //读取对象
- Citation c2 = (Citation) ois.readObject();
- //获取c2奖状所属学生对象
- Student stu1 = c2.getStu();
- stu1.setName("李四");
-
- //判断stu对象和stu1对象是否是同一个对象
- System.out.println("stu和stu1是同一个对象?" + (stu == stu1));
-
- c1.show();
- c2.show();
- }
- }
运行结果为:

注意:Citation类和Student类必须实现Serializable接口,否则会抛NotSerializableException异常。
将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。

建造者(Builder)模式包含如下角色:
类图如下:

创建共享单车
生产自行车是一个复杂的过程,它包含了车架,车座等组件的生产。而车架又有碳纤维,铝合金等材质的,车座有橡胶,真皮等材质。对于自行车的生产就可以使用建造者模式。
这里Bike是产品,包含车架,车座等组件;Builder是抽象建造者,MobikeBuilder和OfoBuilder是具体的建造者;Director是指挥者。类图如下:

具体的代码如下:
- //自行车类
- public class Bike {
- private String frame;
- private String seat;
-
- public String getFrame() {
- return frame;
- }
-
- public void setFrame(String frame) {
- this.frame = frame;
- }
-
- public String getSeat() {
- return seat;
- }
-
- public void setSeat(String seat) {
- this.seat = seat;
- }
- }
-
- // 抽象 builder 类
- public abstract class Builder {
-
- protected Bike mBike = new Bike();
-
- public abstract void buildFrame();
- public abstract void buildSeat();
- public abstract Bike createBike();
- }
-
- //摩拜单车Builder类
- public class MobikeBuilder extends Builder {
-
- @Override
- public void buildFrame() {
- mBike.setFrame("铝合金车架");
- }
-
- @Override
- public void buildSeat() {
- mBike.setSeat("真皮车座");
- }
-
- @Override
- public Bike createBike() {
- return mBike;
- }
- }
-
- //ofo单车Builder类
- public class OfoBuilder extends Builder {
-
- @Override
- public void buildFrame() {
- mBike.setFrame("碳纤维车架");
- }
-
- @Override
- public void buildSeat() {
- mBike.setSeat("橡胶车座");
- }
-
- @Override
- public Bike createBike() {
- return mBike;
- }
- }
-
- //指挥者类
- public class Director {
- private Builder mBuilder;
-
- public Director(Builder builder) {
- mBuilder = builder;
- }
-
- public Bike construct() {
- mBuilder.buildFrame();
- mBuilder.buildSeat();
- return mBuilder.createBike();
- }
- }
-
- //测试类
- public class Client {
- public static void main(String[] args) {
- showBike(new OfoBuilder());
- showBike(new MobikeBuilder());
- }
- private static void showBike(Builder builder) {
- Director director = new Director(builder);
- Bike bike = director.construct();
- System.out.println(bike.getFrame());
- System.out.println(bike.getSeat());
- }
- }
注意:
上面示例是 Builder模式的常规用法,指挥者类 Director 在建造者模式中具有很重要的作用,它用于指导具体构建者如何构建产品,控制调用先后次序,并向调用者返回完整的产品类,但是有些情况下需要简化系统结构,可以把指挥者类和抽象建造者进行结合
- // 抽象 builder 类
- public abstract class Builder {
-
- protected Bike mBike = new Bike();
-
- public abstract void buildFrame();
- public abstract void buildSeat();
- public abstract Bike createBike();
-
- public Bike construct() {
- this.buildFrame();
- this.BuildSeat();
- return this.createBike();
- }
- }
说明:
这样做确实简化了系统结构,但同时也加重了抽象建造者类的职责,也不是太符合单一职责原则,如果construct() 过于复杂,建议还是封装到 Director 中。
优点:
缺点:
造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。
建造者模式除了上面的用途外,在开发中还有一个常用的使用方式,就是当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用建造者模式进行重构。
重构前代码如下:
- public class Phone {
- private String cpu;
- private String screen;
- private String memory;
- private String mainboard;
-
- public Phone(String cpu, String screen, String memory, String mainboard) {
- this.cpu = cpu;
- this.screen = screen;
- this.memory = memory;
- this.mainboard = mainboard;
- }
-
- public String getCpu() {
- return cpu;
- }
-
- public void setCpu(String cpu) {
- this.cpu = cpu;
- }
-
- public String getScreen() {
- return screen;
- }
-
- public void setScreen(String screen) {
- this.screen = screen;
- }
-
- public String getMemory() {
- return memory;
- }
-
- public void setMemory(String memory) {
- this.memory = memory;
- }
-
- public String getMainboard() {
- return mainboard;
- }
-
- public void setMainboard(String mainboard) {
- this.mainboard = mainboard;
- }
-
- @Override
- public String toString() {
- return "Phone{" +
- "cpu='" + cpu + '\'' +
- ", screen='" + screen + '\'' +
- ", memory='" + memory + '\'' +
- ", mainboard='" + mainboard + '\'' +
- '}';
- }
- }
-
- public class Client {
- public static void main(String[] args) {
- //构建Phone对象
- Phone phone = new Phone("intel","三星屏幕","金士顿","华硕");
- System.out.println(phone);
- }
- }
上面在客户端代码中构建Phone对象,传递了四个参数,如果参数更多呢?代码的可读性及使用的成本就是比较高。
重构后代码:
- public class Phone {
-
- private String cpu;
- private String screen;
- private String memory;
- private String mainboard;
-
- private Phone(Builder builder) {
- cpu = builder.cpu;
- screen = builder.screen;
- memory = builder.memory;
- mainboard = builder.mainboard;
- }
-
- public static final class Builder {
- private String cpu;
- private String screen;
- private String memory;
- private String mainboard;
-
- public Builder() {}
-
- public Builder cpu(String val) {
- cpu = val;
- return this;
- }
- public Builder screen(String val) {
- screen = val;
- return this;
- }
- public Builder memory(String val) {
- memory = val;
- return this;
- }
- public Builder mainboard(String val) {
- mainboard = val;
- return this;
- }
- public Phone build() {
- return new Phone(this);}
- }
- @Override
- public String toString() {
- return "Phone{" +
- "cpu='" + cpu + '\'' +
- ", screen='" + screen + '\'' +
- ", memory='" + memory + '\'' +
- ", mainboard='" + mainboard + '\'' +
- '}';
- }
- }
-
- public class Client {
- public static void main(String[] args) {
- Phone phone = new Phone.Builder()
- .cpu("intel")
- .mainboard("华硕")
- .memory("金士顿")
- .screen("三星")
- .build();
- System.out.println(phone);
- }
- }
重构后的代码在使用起来更方便,某种程度上也可以提高开发效率。从软件设计上,对程序员的要求比较高。
工厂方法模式注重的是整体对象的创建方式;而建造者模式注重的是部件构建的过程,意在通过一步一步地精确构造创建出一个复杂的对象。
我们举个简单例子来说明两者的差异,如要制造一个超人,如果使用工厂方法模式,直接产生出来的就是一个力大无穷、能够飞翔、内裤外穿的超人;而如果使用建造者模式,则需要组装手、头、脚、躯干等部分,然后再把内裤外穿,于是一个超人就诞生了。
抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式则是不需要关心构建过程,只关心什么产品由什么工厂生产即可。
建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。
如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车。
非常感谢您阅读到这里,创作不易!如果这篇文章对您有帮助,希望能留下您的点赞👍 关注💖 收藏 💕评论💬感谢支持!!!
听说 三连能够给人 带来好运!更有可能年入百w,进入大厂,上岸
