Java的11种设计模式学习

`话不多说直奔主题。`

Java的11种设计模式学习

action.png

目录

一、工厂设计模式

二、抽象工厂模式

三、单例设计模式

四、建造者(Builder)模式

五、原型模式

六、适配器设计模式

七、桥接(Bridge)设计模式

八、责任链模式

九、迭代器设计模式

十、观察者模式

十一、策略设计模式

一、工厂设计模式

在工厂设计模式中,我们没有把创建对象暴露给客户端,而是通过接口的形式创建引入新的对象。接下来我将创建一个Product接口,写ABC三种产品类 实现接口,它们将会把信息传递给ProductFactory,通过ProductFactory来根据情况获取产品。

1.1 创建一个接口

Product.java

public interface Product {

void product();

}

1.2 创建ABC三种产品类 只写一个A,BC同理。实现Product接口

ProductImplA.java

public class ProductImplA implements Product {

@Override

public void product() {

System.out.println("this is ProductImplA");

}

}

1.3 创建工厂类

ProductFactory.java 根据工厂指定的类型,生成对象。

public class ProductFactory {

public Product getProduct(String productType) {

if (TextUtils.isEmpty(productType)) {

return null;

}

if ("A".equals(productType)) {

return new ProductImplA();

} else if ("B".equals(productType)) {

return new ProductImplB();

} else if ("C".equals(productType)) {

return new ProductImplC();

}

return null;

}

}

1.4 使用工厂,通过传递的信息获取具体类的信息

private void FactoryDemo() {

ProductFactory productFactory = new ProductFactory();

productFactory.getProduct("A").product();

productFactory.getProduct("B").product();

productFactory.getProduct("C").product();

}

-1.5 验证信息

I/System.out: this is ProductImplA

I/System.out: this is ProductImplB

I/System.out: this is ProductImplC

二、抽象工厂模式

抽象工厂是一个大厂,用来创建其他工厂,可以理解为工厂的工厂。

接下来我将创建两个小厂子Product与Color,与(一)工厂设计模式一样,接口并实现ABC。之后创建一个抽象工厂类AbstractFactory,将ProductFactory和ColorFactory定义成自扩展的AbstractFactory,之后在创建 工厂创建者FactoryProducer。

2.1 照着(一)工厂设计模式写个Color,Product工厂直接拿来用。

创建一个接口Color.java

public interface Color {

void color();

}

2.2 创建ABC三种产品颜色,只写个A,BC同理 实现Color接口

ColorImplA.java

public class ColorImplA implements Color {

@Override

public void color() {

System.out.println("class ColorImplA , method color");

}

}

2.3 创建抽象工厂

AbstractFactory.java

public abstract class AbstractFactory {

public abstract Color getColor(String colorType);

public abstract Product getProduct(String productType);

}

-2.4 创建ColorFactory工厂 注意继承类,Product同理,但需要注意抽象方法

ColorFactory.java

public class ProductFactory extends AbstractFactory {

@Override

public Color getColor(String colorType) {

return null;

}

@Override

public Product getProduct(String productType) {

if (TextUtils.isEmpty(productType)) {

return null;

}

if ("productA".equals(productType)) {

return new ProductImplA();

} else if ("productB".equals(productType)) {

return new ProductImplB();

} else if ("productC".equals(productType)) {

return new ProductImplC();

}

return null;

}

}

-2.5 创建 创建工厂者, 根据传递信息获取具体工厂

FactoryProducer.java

public class FactoryProducer {

public static AbstractFactory getType(String choice) {

if ("color".equals(choice)) {

return new ColorFactory();

} else if ("product".equals(choice)) {

return new ProductFactory();

}

return null;

}

}

2.6 使用

private void AbstractFactory() {

AbstractFactory colorProducer = FactoryProducer.getType("color");

colorProducer.getColor("colorA").color();

colorProducer.getColor("colorB").color();

colorProducer.getColor("colorC").color();

AbstractFactory productProducer = FactoryProducer.getType("product");

productProducer.getProduct("productA").product();

productProducer.getProduct("productB").product();

productProducer.getProduct("productC").product();

}

2.7验证信息

I/System.out: class ColorImplA , method color

I/System.out: class ColorImplB , method color

I/System.out: class ColorImplC , method color

I/System.out: class ProductImplA , method product

I/System.out: class ProductImplB , method product

I/System.out: class ProductImplC , method product

三、单例设计模式

Java中最简单的设计模式之一,这种模式只涉及一个类,它负责创建一个对象,同时保证只有一个对象,这个类提供一种方法来访问它的唯一对象,可以直接访问而不需要实例化对象,实例化对象也只有一次。

3.1 饿汉式单例

public class SingleClass {

private static SingleClass singleClass = new SingleClass();

public static SingleClass getInstance() {

return singleClass;

}

}

3.2懒汉式单例

public class SingleClass {

private static SingleClass singleClass;

public static SingleClass getInstance() {

if (null == singleClass) {

singleClass = new SingleClass();

}

return singleClass;

}

}

四、建造者(Builder)模式

建造者模式的UML直观图

Java的11种设计模式学习

image.png

核心思想:将复杂对象的构造与表现分离,使同样的构造可以产生不同的表现。

4.1 创建核心抽象类 , 主要就是说把小步骤给抽象出来,通过调用方法来确定都生成什么表现。

AbstractBuilder.java

public abstract class AbstractBuilder {

abstract void InstallStudio();

abstract void DownLoadSDK();

abstract void BuildProject();

public abstract Project getProject();

}

4.2 创建Project类, 在这里写数据逻辑

Project.java

public class Project {

private List step = new ArrayList<>();

public void add(String info) {

step.add(info);

}

public void show() {

for (int i = 0; i < step.size(); i++) {

Log.e("step" + (i + 1), "show: " + step.get(i));

}

Log.e("step", "show: 安装完成!!!");

}

}

4.3 为了更直观表达建造者模式,我把业务层写到了一起。

Controller.java

public class Controller extends AbstractBuilder {

private Project project;

public Controller() {

project = new Project();

}

@Override

void InstallStudio() {

project.add("安装Studio");

}

@Override

void DownLoadSDK() {

project.add("下载SDK");

}

@Override

void BuildProject() {

project.add("build项目");

}

@Override

public Project getProject() {

return project;

}

public static class Builder {

private AbstractBuilder abstractBuilder;

public Builder(AbstractBuilder abstractBuilder) {

this.abstractBuilder = abstractBuilder;

}

public Builder create() {

abstractBuilder.InstallStudio();

abstractBuilder.DownLoadSDK();

abstractBuilder.BuildProject();

return this;

}

public Builder getProject() {

abstractBuilder.getProject();

return this;

}

public Builder show() {

abstractBuilder.getProject().show();

return this;

}

}

}

4.4 调用

Controller.Builder builder = new Controller.Builder(new Controller());

builder.create().getProject().show();

4.5 验证信息

step1: show: 安装Studio

step2: show: 下载SDK

step3: show: build项目

step: show: 编译完成!!!

五、原型模式

核心思想:复制粘贴都用过,复制的文件跟原文件没有一点差别。

概念:用原型实例 指定创建对象的种类,并通过拷贝这些原型创建新的对象。

5.1 浅拷贝

只拷贝对象中的基本数据类型(8种),对于数组、容器、引用对象等都不会拷贝

5.1.1浅拷贝的代码实现 创建附件类

AttachType.java

public class AttachType {

**get,set,tostring方法隐藏,但实际有

private String attach;

}

5.1.2 定义抽象原型

Student.java

public class Student implements Cloneable {

**get,set,tostring方法隐藏,但实际有

private AttachType attachType;

private String name;

public Student clone() {

Student student = null;

try {

student = (Student) super.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

return student;

}

}

5.1.3 模拟实现

private void catalog() {

Student student1 = new Student();

AttachType attachType = new AttachType("aaa");

student1.setName("张三");

student1.setAttachType(attachType);

Student student2 = student1.clone();

student2.setName("李四");

student2.getAttachType().setAttach("bbb");

System.out.println(">>>s1" + student1.toString());

System.out.println(">>>s2" + student2.toString());

}

-5.1.4 输出结果

I/System.out: >>>s1Student{attachType=AttachType{attach='bbb'}, name='张三'}

I/System.out: >>>s2Student{attachType=AttachType{attach='bbb'}, name='李四'}

可以看到只改动了name,AttachType对象,并没有分离出来。

5.2深克隆

拷贝对象中的基本数据类型(8种),对于数组、容器、引用对象等都会拷贝。

深克隆需要注意的是,所有的类,都要实现Cloneable,并且在宿主bean做处理。

5.2.1创建附件类

AttachType_2.java

public class AttachType_2 implements Cloneable {

** get,set,tostring方法隐藏,但实际有

private String attach;

@Override

protected Object clone() throws CloneNotSupportedException {

return super.clone();

}

}

-5.2.2定义抽象原型

Student_2.java

public class Student_2 implements Cloneable {

** get,set,tostring方法隐藏,但实际有

private AttachType attachType;

private String name;

public Student_2 clone() {

Student_2 student_2 = null;

try {

student_2 = (Student_2) super.clone();

student_2.setAttachType((AttachType) student_2.getAttachType().clone());

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

return (Student_2) student_2;

}

}

5.3调用同步5.1.2

5.4验证结果

I/System.out: >>>s1Student{attachType=AttachType{attach='aaa'}, name='张三'}

I/System.out: >>>s2Student{attachType=AttachType{attach='bbb'}, name='李四'}

处理之后,AttachType_2也被拷贝了。

在某种情况下,合理使用可节省避免不必要的开支。

六、适配器设计模式

概念:负责连接独立或不兼容的接口。

可分为对象适配和类适配模式。

三个角色,目标接口或类、适配类或接口、适配器

对象适配

6.1 简单目标类

目标类处理将语言都转换成英文,属于独立的类。

ConvertEnglish.java

public class ConvertEnglish {

void convertToEnglish(String info) {

System.out.println(">>>转换成英文 : " + info);

}

}

6.1.2 简单适配接口

需要将我说的汉语都转换成英语

public interface SpeakChinese {

void speakChinese(String chinese);

}

6.1.3 适配器

将功能委托给目标来完成实现。

public class TransformationAdapter implements SpeakChinese {

private ConvertEnglish convertEnglish;

public TransformationAdapter(ConvertEnglish convertEnglish) {

this.convertEnglish = convertEnglish;

}

@Override

public void speakChinese(String chinese) {

convertEnglish.convertToEnglish(chinese);

}

}

6.1.4 使用

TransformationAdapter adapter = new TransformationAdapter(new ConvertEnglish());

adapter.speakChinese("我需要转换成英文");

I/System.out: >>>转换成英文 : 我需要转换成英文

对象适配器可以传入多个不同的对象,用来帮忙处理。

类适配

6.2.1 还是刚才的类,只需要改动适配器即可

public class TransformationAdapter extends ConvertEnglish implements SpeakChinese {

@Override

public void speakChinese(String chinese) {

super.convertToEnglish(chinese);

}

}

可以看到是通过extends的方式来获取目标类的属性,但是java中不支持多继承,所以在使用类适配的时候,每一个目标类需要单独写一个。

七、桥接模式

概念:使得具体实现类和接口实现类独立。

7.1 需要一个接口

Animation.java

public interface Animation {

void onDraw(int radius, int x, int y);

}

7.2声明两个接口实现类

RotateImpl.java 和 TranslationImpl.java

public class RotateImpl implements Animation {

@Override

public void onDraw(int radius, int x, int y) {

System.out.println(">>>DrawingRotate:" + radius + "," + x + "," + y);

}

}

public class TranslationImpl implements Animation {

@Override

public void onDraw(int radius, int x, int y) {

System.out.println(">>>DrawingTranslation:" + radius + "," + x + "," + y);

}

}

7.3 桥梁抽象类

AbstractShape.java

public abstract class AbstractShape {

protected Animation animation;

public AbstractShape(Animation animation) {

this.animation = animation;

}

abstract void onDraw();

}

7.4 桥梁具体实现类

ShapeImpl.java

public class ShapeImpl extends AbstractShape {

private int radius, x, y;

public ShapeImpl(int radius, int x, int y, Animation animation) {

super(animation);

this.radius = radius;

this.x = x;

this.y = y;

}

@Override

public void onDraw() {

animation.onDraw(radius, x, y);

}

}

7.5使用

ShapeImpl rotate = new ShapeImpl(9, 100, 100, new RotateImpl());

ShapeImpl translate = new ShapeImpl(15, 200, 300, new TranslationImpl());

rotate.onDraw();

translate.onDraw();

···

log

>>>DrawingRotate:9,100,100

>>>DrawingTranslation:15,200,300

使得具体实现类与接口实现类解耦,两种类都可以在结构上发生改变并且互不影响。

八、责任链模式

概念:将同一请求形成一条链,由链进行传递,能处理的处理,处理不了的继续传递。

8.1 写个请求bean,用来处理同一类请求

RequestBean.java

public class RequestBean {

** 省略了get set

//小于18岁 大约18岁小于30岁 大于30岁小于60岁的

private String name;

private int age;

private String remark;

{

8.2责任链抽象类

AbstractHandler.java

public abstract class AbstractHandler {

protected String handlerName;//当前处理的是谁

protected AbstractHandler nextMessage;//捆绑

public AbstractHandler(String handlerName) {

this.handlerName = handlerName;

}

public void setNextMessage(AbstractHandler nextMessage) {

this.nextMessage = nextMessage;

}

public abstract void handlerRequest(RequestBean requestBean);//子类核心处理方法

}

8.3 员工ABC 三条处理

StaffA.java

public class StaffA extends AbstractHandler {

public StaffA(String handlerName) {

super(handlerName);

}

@Override

public void handlerRequest(RequestBean requestBean) {

if (requestBean.getAge() < 18) {

System.out.println(">>>由" + this.handlerName + "处理了:" + requestBean.getAge() + "," + requestBean

.getName() + "," + requestBean.getRemark());

} else {

if (this.nextMessage != null) {

this.nextMessage.handlerRequest(requestBean);

}

}

}

}

-8.4 员工B

StaffB.java

public class StaffB extends AbstractHandler {

public StaffB(String handlerName) {

super(handlerName);

}

@Override

public void handlerRequest(RequestBean requestBean) {

if (18 < requestBean.getAge() && requestBean.getAge() < 30) {

System.out.println(">>>由" + this.handlerName + "处理了:" + requestBean.getAge() + "," + requestBean

.getName() + "," + requestBean.getRemark());

} else {

if (this.nextMessage != null) {

this.nextMessage.handlerRequest(requestBean);

}

}

}

}

员工C同理,此处不写了。

8.5 责任关联

private void startChain() {

AbstractHandler a = new StaffA("张三");

AbstractHandler b = new StaffB("李四");

AbstractHandler c = new StaffC("王五");

a.setNextMessage(b);

b.setNextMessage(c);

RequestBean request = new RequestBean();

request.setAge(25);

request.setName("赵二");

request.setRemark("无");

a.handlerRequest(request);

}

8.6 验证结果

I/System.out: >>>由李四处理了:25,赵二,无

九、迭代器设计模式

概念:不需要暴露内部结构的同时,可以让外部遍历数据。

9.1 构建迭代接口

MyIterator.java 和 Container.java

因为是遍历我肯定需要知道还有没有下一条数据。

public interface MyIterator {

boolean hasNext();//判定是否有下一条

Object next();

}

public interface Container {

MyIterator getMyIterator();

}

9.2迭代类

public class ContainerImpl implements Container {

private String[] strings = new String[]{"aa", "bb", "cc", "dd", "ee"};

@Override

public MyIterator getMyIterator() {

return new Iterator();

}

class Iterator implements MyIterator {

private int index;

@Override

public boolean hasNext() {

if (index < strings.length) {

return true;

}

return false;

}

@Override

public Object next() {

if (this.hasNext()) {

return strings[index++];

}

return null;

}

}

}

hasNext处理我是否还有下一条数据,在有的前提下我才可以在next方法中return出去,至于为啥要++,next方法肯定在循环中呗。

9.3使用

ContainerImpl container = new ContainerImpl();

for (MyIterator myIterator = container.getMyIterator(); myIterator.hasNext(); ) {

String next = (String) myIterator.next();

System.out.println(">>>next" + next);

}

9.4验证信息

I/System.out: >>>nextaa

I/System.out: >>>nextbb

I/System.out: >>>nextcc

I/System.out: >>>nextdd

I/System.out: >>>nextee

十、观察者模式

概念:如果一个对象被修改,它的依赖对象将会被自动通知。

自动通知其实就是在 合理的时间调用通知接口,直接上代码。

10.1 抽象类

MyObserver.java

依赖对象会被自动通知?所以 抽象肯定有一个依赖类,一个通知接口

public abstract class MyObserver {

protected Subscriber subscriber;

abstract void update();

}

10.2 依赖类

public class Subscriber {

private MyObserver myObserver;

private int state;

public int getState() {

return state;

}

public void setState(int state) {

this.state = state;

notifyAllObserver();

}

//绑定

public void attach(MyObserver myObserver) {

this.myObserver = myObserver;

}

//通知

public void notifyAllObserver() {

myObserver.update();

}

}

可以看到,引入MyObserver抽象类,通过调用MyObserver.update来做通知,所以合理的地方调用notifyAllObserver很重要。

10.3 抽象具体类

ObserverImpl.java

public class ObserverImpl extends MyObserver {

public ObserverImpl(Subscriber subscriber) {

this.subscriber = subscriber;

this.subscriber.attach(this);

}

@Override

public void update() {

System.out.println(">>>this update now");

}

}

10.4 使用

private Subscriber subscriber;//成员变量,点击的时候做通知

subscriber = new Subscriber();

new ObserverImpl(subscriber);

btn.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

subscriber.setState(1);

}

});

subscriber 写成了成员变量,在click view的时候,做了setState值更新。更新就是通知该 调用update接口了。

-10.5 验证信息

I/System.out: >>>this update now

十一、策略设计模式

概念:针对一组算法,将每一种算法都封装到具有共同接口的独立的类中,从而是它们可以相互替换。策略模式的最大特点是使得算法可以在不影响客户端的情况下发生变化,从而改变不同的功能。

11.1 定义共有接口类

IStrategy.java

共有接口类,计算不同的a,b参数处理方式

public interface IStrategy {

void strategyType(int a, int b);

}

11.2 共有接口类ab计算,策略之一

StrategyA.java 加法

public class StrategyA implements IStrategy {

@Override

public void strategyType(int a, int b) {

//处理算法。

int sum = a + b;

System.out.println(">>>sum" + sum);

}

}

11.3共有接口类ab计算,策略之一

StrategyB.java 乘法

public class StrategyB implements IStrategy {

@Override

public void strategyType(int a, int b) {

//处理算法。

int sum = a * b;

System.out.println(">>>sum" + sum);

}

}

还写了个减法,同步上面都一样。主要是为了表现策略之一。

11.4 策略调用类

StrategyImpl.java

public class StrategyImpl {

private IStrategy iStrategy;

public StrategyImpl(IStrategy iStrategy) {

this.iStrategy = iStrategy;

}

public void strategyType(int a, int b) {

iStrategy.strategyType(a, b);

}

}

11.5使用

private void strategy() {

int a = 10;

int b = 5;

StrategyImpl strategy = new StrategyImpl(new StrategyA());

strategy.strategyType(a, b);

StrategyImpl strategy2 = new StrategyImpl(new StrategyB());

strategy2.strategyType(a, b);

StrategyImpl strategy3 = new StrategyImpl(new StrategyC());

strategy3.strategyType(a, b);

}

11.6验证信息

I/System.out: >>>sum15

I/System.out: >>>sum50

I/System.out: >>>sum5

策略模式的好处是 实现可以自由切换,扩展性也比较好,阅读代码很直观。

结语

设计模式 真的是可以规范代码,并且提高对源码的理解。