创建型设计模式:关注对象的实例化过程。
创建型设计模式共5种:工厂方法设计模式,抽象工厂设计模式,构建者设计模式,原型设计模式和单例设计模式。
助记:
一、工厂方法设计模式
英文名:Factory Method Pattern。
1.1、痛点
不使用new
等直接方法创建目标类的实例对象,而是使用工厂方法创建,针对痛点:
- 便于使用
- 便于扩展
1.2、实现
有两种实现形式:
1.2.1、实例工厂方法实现形式
分“目标类只有1个”和“目标类不只1个,且具有共同父类”两种情况进行介绍。
1.2.1.1、目标类只有1个
示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class User { String name;
int age; }
class UserFactory {
User createUser() { User user = new User(); user.name = "dslztx"; user.age = 35;
return user; } }
public class FactoryMethodExample { public static void main(String[] args) { UserFactory userFactory = new UserFactory(); User user = userFactory.createUser(); } }
|
1.2.1.2、目标类不只1个,且具有共同父类
讲解设计模式的教材/材料在介绍工厂方法设计模式时常基于该场景。
示例代码如下[1]:
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 51 52 53 54
| interface Shape { void draw(); }
class Circle implements Shape { @Override public void draw() { System.out.println("Drawing a circle"); } }
class Rectangle implements Shape { @Override public void draw() { System.out.println("Drawing a rectangle"); } }
abstract class ShapeFactory { abstract Shape createShape(); }
class CircleFactory extends ShapeFactory { @Override Shape createShape() { return new Circle(); } }
class RectangleFactory extends ShapeFactory { @Override Shape createShape() { return new Rectangle(); } }
public class FactoryMethodExample { public static void main(String[] args) { ShapeFactory circleFactory = new CircleFactory(); Shape circle = circleFactory.createShape(); circle.draw();
ShapeFactory rectangleFactory = new RectangleFactory(); Shape rectangle = rectangleFactory.createShape(); rectangle.draw(); } }
|
1.2.2、静态工厂方法实现形式
分“目标类只有1个”和“目标类不只1个,且具有共同父类”两种情况进行介绍。
1.2.2.1、目标类只有1个
示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class User { String name;
int age; }
class UserFactoryStatic { static User createUser() { User user = new User(); user.name = "dslztx"; user.age = 35;
return user; } }
public class FactoryMethodExample { public static void main(String[] args) { User user = UserFactoryStatic.createUser(); } }
|
1.2.2.2、目标类不只1个,且具有共同父类
示例代码如下:
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
| interface Shape { void draw(); }
class Circle implements Shape { @Override public void draw() { System.out.println("Drawing a circle"); } }
class Rectangle implements Shape { @Override public void draw() { System.out.println("Drawing a rectangle"); } }
class ShapeFactoryStatic { static <T extends Shape> T createShape(Class<T> tClass) { if (tClass == Circle.class) { return (T) new Circle(); } else if (tClass == Rectangle.class) { return (T) new Rectangle(); } return null; } }
public class FactoryMethodExample { public static void main(String[] args) { Shape circle = ShapeFactoryStatic.createShape(Circle.class); circle.draw();
Shape rectangle = ShapeFactoryStatic.createShape(Rectangle.class); rectangle.draw(); } }
|
1.3、JDK中的例子
JDK中的例子:
Integer.valueOf(int i)
:方便扩展成缓存[-128,127]
值范围内的Integer对象进行复用
Object.toString()
Calendar getInstance()
二、抽象工厂设计模式
英文名:Abstract Factory Pattern。
另外一个名字为:Kit Pattern,工具箱设计模式。
2.1、痛点
实现需求:需要创建一系列相关或相互依赖的对象,这些对象属于一组相关的产品族,同时,系统需要保证这些产品族之间的一致性。
2.2、实现
实现必存在工厂类父类,且该工厂类父类中必存在抽象工厂方法。
注意与“工厂方法设计模式”实现的区分:对于实现必存在工厂类父类,且该工厂类父类中必存在抽象工厂方法
,其属于“工厂方法设计模式”中的实例工厂方法
实现形式;反之,“工厂方法设计模式”中还有静态工厂方法
实现形式,也有非实现必存在工厂类父类,且该工厂类父类中必存在抽象工厂方法
的实例工厂方法
实现形式。故“抽象工厂设计模式”属于“工厂方法设计模式”的子集。
示例代码如下[1]:
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| interface OperatingSystem { void run(); }
interface Application { void open(); }
interface SoftwareFactory { OperatingSystem createOperatingSystem();
Application createApplication(); }
class WindowsOS implements OperatingSystem { @Override public void run() { System.out.println("Running Windows OS"); } }
class LinuxOS implements OperatingSystem { @Override public void run() { System.out.println("Running Linux OS"); } }
class WordApplication implements Application { @Override public void open() { System.out.println("Opening Word Application"); } }
class ExcelApplication implements Application { @Override public void open() { System.out.println("Opening Excel Application"); } }
class WindowsFactory implements SoftwareFactory { @Override public OperatingSystem createOperatingSystem() { return new WindowsOS(); }
@Override public Application createApplication() { return new ExcelApplication(); } }
class LinuxFactory implements SoftwareFactory { @Override public OperatingSystem createOperatingSystem() { return new LinuxOS(); }
@Override public Application createApplication() { return new WordApplication(); } }
public class Client { public static void main(String[] args) { SoftwareFactory windowsFactory = new WindowsFactory(); OperatingSystem windowsOS = windowsFactory.createOperatingSystem(); Application windowsApp = windowsFactory.createApplication();
windowsOS.run(); windowsApp.open();
SoftwareFactory linuxFactory = new LinuxFactory(); OperatingSystem linuxOS = linuxFactory.createOperatingSystem(); Application linuxApp = linuxFactory.createApplication();
linuxOS.run(); linuxApp.open(); } }
|
2.3、JDK中的例子
工厂类父类java.awt.Toolkit
和其中3个抽象工厂方法(实际不只3个,这里只罗列3个进行举例说明):
1 2 3 4 5 6 7 8 9
| public abstract class Toolkit {
protected abstract ButtonPeer createButton(Button target) throws HeadlessException;
protected abstract TextFieldPeer createTextField(TextField target) throws HeadlessException;
protected abstract LabelPeer createLabel(Label target) throws HeadlessException;
}
|
Button产品的父类:
1 2
| public interface ButtonPeer extends ComponentPeer { }
|
TextField产品的父类:
1 2
| public interface TextFieldPeer extends TextComponentPeer { }
|
Label产品的父类:
1 2
| public interface LabelPeer extends ComponentPeer { }
|
2.3.1.1、Windows JDK
java.awt.Toolkit
的具体子类sun.awt.windows.WToolkit
:
1 2
| public final class WToolkit extends SunToolkit implements Runnable { }
|
Button产品的具体子类sun.awt.windows.WButtonPeer
:
1 2
| final class WButtonPeer extends WComponentPeer implements ButtonPeer { }
|
TextField产品的具体子类sun.awt.windows.WTextFieldPeer
:
1 2
| final class WTextFieldPeer extends WTextComponentPeer implements TextFieldPeer { }
|
Label产品的具体子类sun.awt.windows.WLabelPeer
:
1 2
| final class WLabelPeer extends WComponentPeer implements LabelPeer { }
|
2.3.1.2、Linux JDK
java.awt.Toolkit
的具体子类sun.awt.X11.XToolkit
:
1 2
| public final class XToolkit extends UNIXToolkit implements Runnable { }
|
Button产品的具体子类sun.awt.X11.XButtonPeer
:
1 2
| public class XButtonPeer extends XComponentPeer implements ButtonPeer { }
|
TextField产品的具体子类sun.awt.X11.XTextFieldPeer
:
1 2
| final class XTextFieldPeer extends XComponentPeer implements TextFieldPeer { }
|
Label产品的具体子类sun.awt.X11.XLabelPeer
:
1 2
| class XLabelPeer extends XComponentPeer implements LabelPeer { }
|
三、构建者设计模式
英文名:Builder Pattern。
3.1、痛点
适用场景:对于一个实例对象,很难一次性构建完成或者一次性构建完成代价很大。它的本质是将构建实例对象所需的信息从“一次性输入”改为“非一次性输入”。
3.2、实现
有两种实现形式:
- 二角色——Client和Builder,实际经常使用的实现形式
- 三角色——Client,Director和Builder,很多设计模式书籍建议的实现形式,引入Director的本意是将Client和Builder解耦,但也引入了额外的维护成本,故权衡下来,在引入构建者设计模式时经常使用“二角色”实现形式
备注:多见“Builder实例的构建方法返回Builder实例本身”以进行链式调用
3.2.1、“二角色”实现形式
包含Client和Builder两种角色,Builder角色负责构建实例对象,Client角色(即业务代码)直接与Builder角色进行交互。
示例代码如下:
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| class House {
String foundation; String structure; String roof; String interior;
}
class HouseBuilder { private House house = null;
public HouseBuilder() { house = new House(); }
public void buildFoundation(String foundation) { house.foundation = foundation; }
public void buildStructure(String structure) { house.structure = structure; }
public void buildRoof(String roof) { house.roof = roof; }
public void buildInterior(String interior) { house.interior = interior; }
public House getHouse() { return house; } }
public class Client { public static void main(String[] args) {
HouseBuilder houseBuilder = new HouseBuilder();
String foundation = "FakeFoundation"; houseBuilder.buildFoundation(foundation);
String structure = "FakeStructure"; houseBuilder.buildStructure(structure);
String roof = "FakeRoof"; houseBuilder.buildRoof(roof);
String interior = "FakeInterior"; houseBuilder.buildInterior(interior);
System.out.println(houseBuilder.getHouse());
} }
|
3.2.2、“三角色”实现形式
包含Client、Director和Builder三种角色,Builder角色负责构建实例对象,Client角色(即业务代码)通过Director角色与Builder角色进行交互。
示例代码如下:
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| class House {
String foundation; String structure; String roof; String interior;
}
class HouseBuilder { private House house = null;
public HouseBuilder() { house = new House(); }
public void buildFoundation(String foundation) { house.foundation = foundation; }
public void buildStructure(String structure) { house.structure = structure; }
public void buildRoof(String roof) { house.roof = roof; }
public void buildInterior(String interior) { house.interior = interior; }
public House getHouse() { return house; } }
class Director { private HouseBuilder houseBuilder;
public Director(HouseBuilder builder) { this.houseBuilder = builder; }
public House constructHouse() { String foundation = "FakeFoundation"; houseBuilder.buildFoundation(foundation);
String structure = "FakeStructure"; houseBuilder.buildStructure(structure);
String roof = "FakeRoof"; houseBuilder.buildRoof(roof);
String interior = "FakeInterior"; houseBuilder.buildInterior(interior);
return houseBuilder.getHouse(); } }
public class Client { public static void main(String[] args) {
HouseBuilder concreteBuilder = new HouseBuilder();
Director director = new Director(concreteBuilder);
House concreteHouse = director.constructHouse();
System.out.println("Concrete House: " + concreteHouse);
} }
|
3.3、JDK中的例子
3.3.1、StringBuilder
构建一个String实例对象不能一次性输入所有信息,须多次输入,适合使用StringBuilder。
采用“二角色”实现形式的示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Client { public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append("Subject");
sb.append("Content");
sb.append("Footer");
System.out.println(sb.toString());
} }
|
四、原型设计模式
英文名:Prototype Pattern。
4.1、痛点
实现业务需求:根据已存在实例对象克隆“具有一模一样值”的实例对象。
克隆具有克隆深浅的属性,关于克隆深浅有两点说明:
- 越浅的克隆,克隆对象与原对象共享内存越多,两者互相独立性越差;越深的克隆,克隆对象与原对象共享内存越少,两者互相独立性越好
- 经常简单将克隆分为“浅度克隆”和“深度克隆”,其实是错误的,因为“浅度克隆”和“深度克隆”之间没有明确的界限
在以下示例代码中,呈现了对于shallowClone -> deepClone -> deepMoreClone
,克隆越来越深(佐证了难以简单划分“浅度克隆”和“深度克隆”),克隆对象与原对象共享内存越来越少,两者互相独立性越来越好。
示例代码如下:
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
| class User {
String name;
int age;
public User shallowClone() { User user = new User(); user.name = name; user.age = age;
return user; }
}
class UserRepo {
List<User> userList = new ArrayList<User>();
public UserRepo shallowClone() { UserRepo userRepo = new UserRepo(); userRepo.userList = userList;
return userRepo; }
public UserRepo deepClone() { UserRepo userRepo = new UserRepo(); userRepo.userList = new ArrayList<>(userList);
return userRepo; }
public UserRepo deepMoreClone() { UserRepo userRepo = new UserRepo();
List<User> tmpUserList = new ArrayList<>(); for (User user : userList) { tmpUserList.add(user.shallowClone()); }
userRepo.userList = tmpUserList;
return userRepo; }
}
|
4.2、实现
有3种实现形式
- 自实现复制方法
- JDK的
Object.clone()
原生机制
- 第三方复制框架
4.2.1、自实现复制方法
示例代码如下:
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
| class User { String name;
int age; }
public class Client { public static void main(String[] args) {
User user = new User(); user.name = "dslztx"; user.age = 35;
User copiedUser = copy(user); System.out.println(copiedUser.name); System.out.println(copiedUser.age); }
public static User copy(User a) { User user = new User(); user.name = a.name; user.age = a.age; return user; } }
|
4.2.2、JDK的Object.clone()
原生机制
示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class User implements Cloneable { String name;
int age;
@Override public User clone() throws CloneNotSupportedException { return (User) super.clone(); } }
public class Client { public static void main(String[] args) throws CloneNotSupportedException {
User user = new User(); user.name = "dslztx"; user.age = 35;
User copiedUser = user.clone(); System.out.println(copiedUser.name); System.out.println(copiedUser.age); } }
|
4.2.3、第三方复制框架
使用第三方复制框架,比如“Apache commons-beanutils包中的BeanUtils.copyProperties工具方法”。
4.3、JDK中的例子
4.3.1、ArrayList的clone()
方法
重写覆盖Object.clone()
方法实现ArrayList自己的clone()
方法:
1 2 3 4 5 6 7 8 9 10 11
| public Object clone() { try { ArrayList<?> v = (ArrayList<?>) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { throw new InternalError(e); } }
|
五、单例设计模式
英文名:Singleton。
5.1、痛点
实现业务需求:全局具有唯一实例。
5.2、实现
单例有多种实现形式,参见《单例》。
5.3、JDK中的例子
5.3.1、java.lang.Runtime
实例对象
java.lang.Runtime
实例对象是单例的。
1 2 3 4 5 6 7
| public class Runtime { private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() { return currentRuntime; } }
|
参考文献
[1]https://mp.weixin.qq.com/s/H16g_yZwRMIKagPb8oNIYQ
[2]https://www.bilibili.com/read/cv18266097