设计模式回顾
Java总共有23种设计模式,平时经常用到的也就十几种,在此回顾一下,做下总结。
我们从对象的三个特征来总结:
一,创建型模式
顾名思义,就是从对象的创建方式上来看,可以分为哪些类型,应用在什么场景,解决什么问题。
1.单例模式
应用场景:同一对象需要被频繁的使用,假如创建新对象会有大量不必要的内存开销,因此需要在整个应用程序运行的生命周期里保持唯一的一个对象实例。
a.懒汉线程安全式
创建一个静态成员变量,使之在类初始化的时候就生成这个实例,另外加锁使之线程安全。
public class SingleObject {
private static SingleObject instance = new SingleObject();
private SingleObject(){
}
public static SingleObject getInstance(){
return instance;
}
}
b.双重校验锁方式
public class SingleObject {
private volatile static SingleObject instance;
private SingleObject(){
}
public static synchronized SingleObject getInstance(){
if (instance == null){
synchronized (SingleObject.class){
if (instance == null){
instance = new SingleObject();
}
}
}
return instance;
}
}
2.工厂模式
使用场景:
同一工厂生产不同的产品,使用者只需要知道需要什么产品就行了。工厂会根据产品类型用不同的子类去实现产品细节。这种方式的优点在于对外使用方便,对内隐藏细节,扩展性高。
其实就是把具备同种属性的不同对象集合起来对外提供一个调用接口。
image.png
public interface Shape{
void draw();
}
public class Circle implements Shape{
@Override
public void draw() {
System.out.println("circle ...");
}
}
public class Rectangle implements Shape{
@Override
public void draw() {
System.out.println("rectangle ...");
}
}
public class FactoryObject {
public Shape getShape(String type){
if (type.equals("circle")){
return new Circle();
}
if (type.equals("rectangle")){
return new Rectangle();
}
return null;
}
}
3.抽象工厂模式
此模式可以看成是工厂模式的集合。具体来说就是多个工厂的集大成者。举个例子,生产汽车的工厂生产高配,中配,低配三种档次的汽车,按颜色分有红色,黑色,白色三种;按款式分又有A款B款C款。一辆汽车要把这三种特征都体现出来,因此可以将这三种特征抽象成一个接口;每个特征都单独提取一个共同特征让子类去实现,如下图。
image.png
代码如下:
FactoryProvider
public class FactoryProvider {
public static AbstractFactoryClass getFactory(String title){
switch (title){
case "grade":
return new GradeFactory();
case "color":
return new ColorFactory();
case "style":
return new StyleFactory();
}
return null;
}
}
AbstractFactoryClass
public abstract class AbstractFactoryClass {
abstract Grade getGrade(GradeFactory.GradeType type);
abstract Color getColor(ColorFactory.ColorType type);
abstract Style getStyle(StyleFactory.StyleType type);
}
GradeFactory
public class GradeFactory extends AbstractFactoryClass{
enum GradeType{
ONE(1),TWO(2),THREE(3);
private int value;
GradeType(int i) {
value = i;
}
}
@Override
public Grade getGrade(GradeType type) {
Grade grade = null;
switch (type){
case ONE:
grade = new GradeOne();
break;
case TWO:
grade = new GradeTwo();
break;
case THREE:
grade = new GradeThree();
break;
}
return grade;
}
@Override
public Color getColor(ColorFactory.ColorType type) {
return null;
}
@Override
public Style getStyle(StyleFactory.StyleType type) {
return null;
}
}
ColorFactory
public class ColorFactory extends AbstractFactoryClass{
enum ColorType{
RED,WHITE,BLUE;
}
@Override
public Grade getGrade(GradeFactory.GradeType type) {
return null;
}
@Override
public Color getColor(ColorType type) {
Color color = null;
switch (type){
case RED:
color = new ColorRed();
break;
case BLUE:
color = new ColorBlue();
break;
case WHITE:
color = new ColorWhite();
break;
}
return color;
}
@Override
public Style getStyle(StyleFactory.StyleType type) {
return null;
}
}
StyleFactory
public class StyleFactory extends AbstractFactoryClass{
enum StyleType{
A,B,C;
}
@Override
public Grade getGrade(GradeFactory.GradeType type) {
return null;
}
@Override
public Color getColor(ColorFactory.ColorType type) {
return null;
}
@Override
public Style getStyle(StyleType type) {
Style style = null;
switch (type){
case A:
style = new StyleA();
break;
case B:
style = new StyleB();
break;
case C:
style = new StyleC();
break;
}
return style;
}
}
Grade
public interface Grade {
void value();
}
Color
public interface Color {
void value();
}
Style
public interface Style {
void value();
}
以下分别实现了这三个接口的9个类比较简单就不贴出来了,就是GradeOne,GradeTwo,GradeThree;ColorRed,ColorWhite,ColorBlue;StyleA,StyleB,StyleC。最后看看怎么使用,比如我们想拿到A颜色的车。
public class Test {
public static void main(String[] args) {
//获取蓝色车
AbstractFactoryClass colorFactory = FactoryProvider.getFactory("color");
Color color = colorFactory.getColor(ColorFactory.ColorType.BLUE);
color.value();
//获取一等车
AbstractFactoryClass gradeFactory = FactoryProvider.getFactory("grade");
Grade grade = gradeFactory.getGrade(GradeFactory.GradeType.ONE);
grade.value();
//获取A风格车
AbstractFactoryClass styleFactory = FactoryProvider.getFactory("style");
Style style =styleFactory.getStyle(StyleFactory.StyleType.A);
style.value();
}
}
4.建造者模式
Builder模式,该模式类似汉堡店里有很多食物,汉堡包,可乐,薯条等等,每个都可以单点,但是不同的食物也可以组成不同的套餐,假如需要其中的一种套餐但是其他的又不需要,那么只需要将几个参数赋值就行了,如下:
public class Meal {
private String cokeA;//必须
private String hamburgA;//必须
private String hamburgB;//可选
private String cokeB;//可选
private String chips;//可选
public Meal(String cokeA, String hamburgA) {
this.cokeA = cokeA;
this.hamburgA = hamburgA;
}
public String getCokeA() {
return cokeA;
}
public void setCokeA(String cokeA) {
this.cokeA = cokeA;
}
public String getHamburgA() {
return hamburgA;
}
public void setHamburgA(String hamburgA) {
this.hamburgA = hamburgA;
}
public String getHamburgB() {
return hamburgB;
}
public void setHamburgB(String hamburgB) {
this.hamburgB = hamburgB;
}
public String getCokeB() {
return cokeB;
}
public void setCokeB(String cokeB) {
this.cokeB = cokeB;
}
public String getChips() {
return chips;
}
public void setChips(String chips) {
this.chips = chips;
}
}
这个是JavaBean的形式,简单好用,当然弱点也很明显:如果直接构造一个mear对象,那么需要一个个的设置参数,麻烦不说后面还很容易将设置过的值改变掉,因为变量的值对外开放,所以很容易从外面进行篡改;如果用构造函数那么只要参数不同就要几个不一样的构造函数,不胜其烦,因此builder模式就产生了。
实现方法
在Meal 中创建一个静态内部类 Builder,然后将Meal 中的参数都复制到Builder类中。
在Meal中创建一个private的构造函数,参数为Builder类型
在Builder中创建一个public的构造函数,参数为Meal中必填的那些参数,cpu 和ram。
在Meal中创建设置函数,对Meal中那些可选参数进行赋值,返回值为Builder类型的实例
在Meal中创建一个build()方法,在其中构建Meal的实例并返回
public class Meal {
private String cokeA;//必须
private String hamburgA;//必须
private String hamburgB;//可选
private String cokeB;//可选
private String chips;//可选
private Meal(){
}
public String getCokeA() {
return cokeA;
}
public void setCokeA(String cokeA) {
this.cokeA = cokeA;
}
public String getHamburgA() {
return hamburgA;
}
public void setHamburgA(String hamburgA) {
this.hamburgA = hamburgA;
}
public String getHamburgB() {
return hamburgB;
}
public void setHamburgB(String hamburgB) {
this.hamburgB = hamburgB;
}
public String getCokeB() {
return cokeB;
}
public void setCokeB(String cokeB) {
this.cokeB = cokeB;
}
public String getChips() {
return chips;
}
public void setChips(String chips) {
this.chips = chips;
}
public static class Builder{
private String cokeA;//必须
private String hamburgA;//必须
private String hamburgB;//可选
private String cokeB;//可选
private String chips;//可选
public Builder() {
}
public Builder setCokeA(String cokeA) {
this.cokeA = cokeA;
return this;
}
public Builder setHamburgA(String hamburgA) {
this.hamburgA = hamburgA;
return this;
}
public Builder setHamburgB(String hamburgB) {
this.hamburgB = hamburgB;
return this;
}
public Builder setCokeB(String cokeB) {
this.cokeB = cokeB;
return this;
}
public Builder setChips(String chips) {
this.chips = chips;
return this;
}
public Meal build(){
Meal meal = new Meal();
meal.chips = chips;
meal.cokeA = cokeA;
meal.cokeB = cokeB;
meal.hamburgA = hamburgA;
meal.hamburgB = hamburgB;
return meal;
}
}
}
对象生成方法:
Meal meal = new Meal.Builder()
.setChips("chip")
.setCokeA("cokeA")
.build();
这样做的好处有:
1.meal不提供对外的构造方法和参数设置方法,只能通过创建一个builder对象来设置参数,对象一旦生成,就无法更改其变量。
2.书写方便省事,需要设置什么属性一目了然。
5.原型模式
此模式就是一个实现clone()接口的类,作用是克隆一个和之前一样的实例,因它没有构造函数,是从内存中直接复制的,因此可以提高性能,可以应用在当我们的类初始化需要消耗很多的资源的场景下,避免了初始化占有的时间和空间。另外需要注意的是clone分为浅拷贝(只会复制基本类型的变量值,假如是对象值的话就只会复制引用)和深拷贝(不仅会复制基本类型的值,还会复制对象的值),所以要根据需要去实现。
public class Property implements Cloneable {
private String id;
private String type;
private Map<String,Object> datas;
public String getType(){
return type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Property clone() {
Property clone = null;
try {
clone = (Property) super.clone();
clone.datas = (Map<String, Object>) ((HashMap<String,Object>)datas).clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
二,结构型模式
三,行为型模式