[Android基础系列]设计模式(一)

前言

这篇文章可以说是java基础的范畴,为了下一篇Android开发中的常用设计模式做一下铺垫,也顺便反思一下。

正文

设计模式分类

分类方式是多样的,这里我们按照功能类型进行分类:

  • 创建型

    • 工厂方法 Factory Method
    • 抽象工厂 Abstract Factory
    • 建造者 Builder
    • 原型 Prototype
    • 单例 Singleton
  • 结构型
    • 适配器 Adapter Class/Object
    • 桥接 Bridge
    • 组合 Composite
    • 装饰 Decorator
    • 外观 Facade
    • 享元 Flyweight
    • 代理 Proxy
  • 行为型
    • 解释器 Interpreter
    • 模板方法 Template Method
    • 责任链 Chain of Responsibility
    • 命令 Command
    • 迭代器 Iterator
    • 中介者 Mediator
    • 备忘录 Memento
    • 观察者 Observer
    • 状态 State
    • 策略 Strategy
    • 访问者 Visitor

一共23种设计模式。

设计模式概述

创建型

创建型的五种设计模式,其目的都是为了创建对象(生成实例)

工厂方法

简单工厂模式就不谈了,工厂方法模式的UML图:

工厂必然是用来流水化生产的,“风格迥异”的产品不适合使用工厂模式

工厂方法模式与简单工厂模式不同的是:将原有的工厂类,划分为 抽象工厂 和 具体工厂 。其中抽象工厂提供了一个接口,具体工厂负责实现对应的具体的产品。

demo:

抽象工厂接口

package factroy_method;
/**
 * @ClassName: ProductFactoryInterface
 * @Description: 抽象工厂接口
 * @date 2016年5月18日 下午2:03:04
 *
 * @author leobert.lan
 * @version 1.0
 */
public interface ProductFactoryInterface {
    public Product createProduct();
}

实际工厂(这里我举例用两个)

package factroy_method;

/**
 * @ClassName: AProductFactroy
 * @Description: A产品具体工厂
 * @date 2016年5月18日 下午2:06:28
 *
 * @author leobert.lan
 * @version 1.0
 */
public class AProductFactory implements ProductFactoryInterface {

    @Override
    public Product createProduct() {
        return new AProduct();
    }
}

package factroy_method;
/**
 * @ClassName: BProductFactory
 * @Description: B产品具体工厂
 * @date 2016年5月18日 下午2:13:59
 *
 * @author leobert.lan
 * @version 1.0
 */
public class BProductFactory implements ProductFactoryInterface{

    @Override
    public Product createProduct() {
        return new BProduct();
    }

}

“风格类似”的产品的API

package factroy_method;

/**
 * @ClassName: Product
 * @Description: “产品”的API
 * @date 2016年5月18日 下午2:04:36
 *
 * @author leobert.lan
 * @version 1.0
 */
public interface Product {
    void use();
}

实际产品类

package factroy_method;
/**
 * @ClassName: AProduct
 * @Description: 具体产品A
 * @date 2016年5月18日 下午2:10:02
 *
 * @author leobert.lan
 * @version 1.0
 */
public class AProduct implements Product{

    @Override
    public void use() {
        System.out.println("use A");
    }

}

package factroy_method;
/**
 * @ClassName: BProduct
 * @Description: 具体产品“B”
 * @date 2016年5月18日 下午2:12:36
 *
 * @author leobert.lan
 * @version 1.0
 */
public class BProduct implements Product{

    @Override
    public void use() {
        System.out.println("use B");
    }

}

测试一下:

package factroy_method;
/**
 * @ClassName: Test
 * @Description: TODO
 * @date 2016年5月18日 下午2:15:19
 *
 * @author leobert.lan
 * @version 1.0
 */
public class Test {

    public static void main(String[] args) {
        ProductFactoryInterface productFactoryInterface1 = new AProductFactory();
        productFactoryInterface1.createProduct().use();

        ProductFactoryInterface productFactoryInterface2 = new BProductFactory();
        productFactoryInterface2.createProduct().use();
    }

}

输出结果自然是:

use A

use B

我们可以体会到,工厂模式是为了“风格相同”的东西而产生的,我们去使用必然是因为有“风格相同”的东西,每种东西应该是对应了不同的业务场景,可以大胆推测,这些业务也较为类似,潜台词就是:业务类可以进行抽象。

父类只需要拿到抽象工厂接口实例(具体业务子类提供),就可以完成共有的逻辑,不必关心也不应当关心使用的是哪种实例。

有这样一句话:

Factory Method 使一个类的实例化延迟到其子类。

适用性:

  • 当一个类不知道它所必须创建的对象的类的时候。
  • 当一个类希望由它的子类来指定它所创建的对象的时候。
  • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

抽象工厂

抽象工厂模式是一种比工厂模式抽象程度更高的模式。在工厂方法模式中,一个具体的工厂类负责创建一个单独的、具体的产品。有多少种产品,就需要多少个对应的工厂类,即使这些产品之间有某些必要联系。

我们可以这样理解:抽象工厂是对工厂方法的进一步抽象,所以他的层面会高一层。通俗但是不是很准确的说就是:工厂模式是干某件事情的,抽象工厂就是干这一类事情的。

上面我们体会到工厂方法模式用来生产“风格类似”的产品,用一个更常见的词:一类产品簇(也有叫产品族的,我习惯用簇这个词),那么抽象工厂就是指导生产多类产品簇的。

这样理解产品簇:碳酸饮料是一个簇,可以有可口可乐、雪碧等等。

而且我们不可否认,同一个产品也有不同属性,例如可口可乐有不同的容量、不同的产地、不同的生产日期(用工厂方法模式也能去做这件事情,上文没有提及,我们可以在工厂接口中定义生产方法的时候约定形参。之所以在这里补充,是有一些文章将这一点作为工厂方法和抽象工厂的不同,这不是很恰当,但抽象工厂确实可以给产品加上每个工厂自己特有的信息)

demo(有些地方偷了点懒)

抽象工厂接口

package abstract_factory;
/**
 * @ClassName: AbstractFactory
 * @Description: TODO
 * @date 2016年5月18日 下午2:47:19
 *
 * @author leobert.lan
 * @version 1.0
 */
public interface AbstractFactory {

    public IProductClusterOne createClusterOne();

    public IProductClusterTwo createClusterTwo();

}

实际的工厂

package abstract_factory;
/**
 * @ClassName: AmericanFactory
 * @Description: 美国的具体工厂
 * @date 2016年5月18日 下午3:02:32
 *
 * @author leobert.lan
 * @version 1.0
 */
public class AmericanFactory implements AbstractFactory{

    @Override
    public IProductClusterOne createClusterOne() {
        return new AProductOfClusterOne(getClass().getSimpleName());
    }

    @Override
    public IProductClusterTwo createClusterTwo() {
        return new AProductOfClusterTwo(getClass().getSimpleName());
    }

}

package abstract_factory;
/**
 * @ClassName: ChinaFactory
 * @Description: TODO
 * @date 2016年5月18日 下午3:02:06
 *
 * @author leobert.lan
 * @version 1.0
 */
public class ChinaFactory implements AbstractFactory{

    @Override
    public IProductClusterOne createClusterOne() {
        //同一个产品可以有不同的属性,我直接打上工厂特有的信息,但这不是抽象工厂提出的主要目的,可以这样写而已,在某些情况下确实方便。使用抽象工厂,这里应该生成BProduct而非AProduct
        return new AProductOfClusterOne(getClass().getSimpleName());
    }

    @Override
    public IProductClusterTwo createClusterTwo() {
        //实际目的就是生产产品簇中的另一个产品
        return new BProductOfClusterTwo(getClass().getSimpleName());
    }

}

产品簇API

package abstract_factory;

/**
 * @ClassName: IProductClusterOne
 * @Description: TODO
 * @date 2016年5月18日 下午2:59:33
 *
 * @author leobert.lan
 * @version 1.0
 */
public interface IProductClusterOne {
    void readInfo();

    /**
     * @Title: getYieldly
     * @Description: 获取生产地信息
     * @author: leobert.lan
     * @return
     */
    String getYieldly();

}

package abstract_factory;
/**
 * @ClassName: IProductClusterTwo
 * @Description: 第二类产品簇的API,当然,我只是偷懒和第一类写的一样
 * @date 2016年5月18日 下午2:59:40
 *
 * @author leobert.lan
 * @version 1.0
 */
public interface IProductClusterTwo {

    void readInfo();

    String getYieldly();

}

实际产品

package abstract_factory;
/**
 * @ClassName: AProductOfClusterOne
 * @Description: TODO
 * @date 2016年5月18日 下午3:13:41
 *
 * @author leobert.lan
 * @version 1.0
 */
public class AProductOfClusterOne implements IProductClusterOne{

    private final String yieldly;

    public AProductOfClusterOne(String yieldly) {
        this.yieldly = yieldly;
    }

    @Override
    public void readInfo() {
        System.out.println("i am"+getClass().getSimpleName()+"made in " + getYieldly());
    }

    @Override
    public String getYieldly() {
        return yieldly;
    }

}

package abstract_factory;
/**
 * @ClassName: AProductOfClusterOne
 * @Description: TODO
 * @date 2016年5月18日 下午3:13:41
 *
 * @author leobert.lan
 * @version 1.0
 */
public class AProductOfClusterTwo implements IProductClusterTwo{

    private final String yieldly;

    public AProductOfClusterTwo(String yieldly) {
        this.yieldly = yieldly;
    }

    @Override
    public void readInfo() {
        System.out.println("i am"+getClass().getSimpleName()+"made in " + getYieldly());
    }

    @Override
    public String getYieldly() {
        return yieldly;
    }

}

package abstract_factory;
/**
 * @ClassName: BProductOfClusterOne
 * @Description: TODO
 * @date 2016年5月18日 下午3:15:38
 *
 * @author leobert.lan
 * @version 1.0
 */
public class BProductOfClusterOne implements IProductClusterOne{

    private final String yieldly;

    public BProductOfClusterOne(String yieldly) {
        this.yieldly = yieldly;
    }

    @Override
    public void readInfo() {
        System.out.println("i am"+getClass().getSimpleName()+"made in " + getYieldly());
    }

    @Override
    public String getYieldly() {
        return yieldly;
    }

}

package abstract_factory;
/**
 * @ClassName: BProductOfClusterOne
 * @Description: TODO
 * @date 2016年5月18日 下午3:15:38
 *
 * @author leobert.lan
 * @version 1.0
 */
public class BProductOfClusterTwo implements IProductClusterTwo{

    private final String yieldly;

    public BProductOfClusterTwo(String yieldly) {
        this.yieldly = yieldly;
    }

    @Override
    public void readInfo() {
        System.out.println("i am"+getClass().getSimpleName()+"made in " + getYieldly());
    }

    @Override
    public String getYieldly() {
        return yieldly;
    }

}

测试一下

package abstract_factory;
/**
 * @ClassName: Test
 * @Description: TODO
 * @date 2016年5月18日 下午3:27:29
 *
 * @author leobert.lan
 * @version 1.0
 */
public class Test {

    public static void main(String[] args) {
        AbstractFactory factory1 = new AmericanFactory();
        AbstractFactory factory2 = new ChinaFactory();

        factory1.createClusterOne().readInfo();
        factory2.createClusterOne().readInfo();

        factory1.createClusterTwo().readInfo();
        factory2.createClusterTwo().readInfo();

    }

}

结果:(抱歉没处理好空格。。。)

i amAProductOfClusterOnemade in AmericanFactory

i amAProductOfClusterOnemade in ChinaFactory

i amAProductOfClusterTwomade in AmericanFactory

i amBProductOfClusterTwomade in ChinaFactory

-

意图

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

适用性

一个系统要独立于它的产品的创建、组合和表示时。

一个系统要由多个产品系列中的一个来配置时。

对比一下两者:

工厂方法 :用来生产同一等级结构中的固定产品。(支持增加任意产品,一个工厂对应一个产品,加产品就加工厂)

抽象工厂 :用来生产不同产品簇的全部产品。(对于增加新的产品,无能为力[这里指在某个具体的工厂中生产一个产品簇中的多个产品];支持增加产品簇)

建造者

对于复杂的创建,我们可以使用这个

可以想象一下,有一个类有很多个属性,嗯,看到构造器真是屎一样的代码,你无法避免这种情况:这么多属性都是final修饰的!好吧,客观的说你是可以使用大量的重载构造器方法以填写默认值,你也可以不使用final修饰在构造后不停的set,但是无法否认你写的时候心里都难受。

对于建造者模式的实现,略有差异,但我更喜欢在预设建造过程的时候返回建造者对象

demo

建造者接口

package builder;

/**
 * @ClassName: IHeHeBuilder
 * @Description: TODO
 * @date 2016年5月18日 下午4:24:55
 *
 * @author leobert.lan
 * @version 1.0
 */
public interface IHeHeBuilder {
    IHeHeBuilder setAttrA(String attra);

    IHeHeBuilder setAttrB(String attrb);

    IHeHeBuilder setAttrC(String attrc);

    IHeHeBuilder setAttrD(String attrd);

    //....

    HeHe build(); //build or create

}

想要建造的类

package builder;

/**
 * @ClassName: HeHe
 * @Description: TODO
 * @date 2016年5月18日 下午4:24:11
 *
 * @author leobert.lan
 * @version 1.0
 */
public class HeHe {

    private final String attrA;

    private final String attrB;

    private final String attrC;

    private final String attrD;

    public HeHe(String attrA, String attrB, String attrC, String attrD) {
        super();
        this.attrA = attrA;
        this.attrB = attrB;
        this.attrC = attrC;
        this.attrD = attrD;
    }

    public void readInfo() {
        String s = "a:" + attrA + ",b:" + attrB + ",c" + attrC + ",d:" + attrD;
        System.out.println(s);
    }

    public static class Builder implements IHeHeBuilder {
        private String attrA = "defaulta";

        private String attrB = "defaultb";

        private String attrC = "defaultc";

        private String attrD = "defaultd";

        public Builder() {
            super();
        }
        // 省略N种情况,强迫症患者最好只写上面那个,也就是一个都不写

        public Builder(String attrA, String attrB, String attrC, String attrD) {
            super();
            this.attrA = attrA;
            this.attrB = attrB;
            this.attrC = attrC;
            this.attrD = attrD;
        }

        public IHeHeBuilder setAttrA(String attrA) {
            this.attrA = attrA;
            return this;
        }

        public IHeHeBuilder setAttrB(String attrB) {
            this.attrB = attrB;
            return this;
        }

        public IHeHeBuilder setAttrC(String attrC) {
            this.attrC = attrC;
            return this;
        }

        public IHeHeBuilder setAttrD(String attrD) {
            this.attrD = attrD;
            return this;
        }

        @Override
        public HeHe build() {
            return new HeHe(attrA, attrB, attrC, attrD);
        }

    }
}

测试一下

package builder;

/**
 * @ClassName: Test
 * @Description: TODO
 * @date 2016年5月18日 下午4:36:36
 *
 * @author leobert.lan
 * @version 1.0
 */
public class Test {

    public static void main(String[] args) {
        IHeHeBuilder builder = new HeHe.Builder();
        builder.setAttrA("this is test attr a").setAttrC("hehe").build().readInfo();

    }

}

写起来还是挺舒服的

来一段高大上的

意图

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

适用性

当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。

当构造过程必须允许被构造的对象有不同的表示时。

原型

原型模式有两种表现形式(本质还是一致的):简单形式,登记形式,上面的图是简单形式的。

值得一提的是,这是一种“复制”的工作方式。复制有浅复制和深复制之分。我们说对象的字段可以分为值类型和引用类型的。浅复制和深复制对值类型的都是拷贝值,是相互独立的,而浅复制的引用类型字段是指向了同一个内存地址,一个变了就都变了,但深复制还是将依赖对象的“内容”进行复制,相互独立。

我们知道java中的Object类中定义了clone方法,Cloneable接口也是一个空的接口。我们抛开这些东西,重新实现一下。

我们主要看一下深浅复制的差别,就不建造多个原型类来展示它的真正意义

demo

package prototype;
/**
 * @ClassName: Prototype
 * @Description: TODO
 * @date 2016年5月19日 上午8:47:38
 *
 * @author leobert.lan
 * @version 1.0
 */
public interface Prototype {

    public Object shallowClone();

    public Object deepClone();

}

原型类(真正使用的时候会建立多个原型类来当作“模板”,参数基本都是固定的,制式的风格)

package prototype;

/**
 * @ClassName: APrototype
 * @Description: TODO
 * @date 2016年5月19日 上午10:45:19
 *
 * @author leobert.lan
 * @version 1.0
 */
public class APrototype implements Prototype {

    private String s;

    // 一个default 的引用
    private Reliant reliant = new Reliant(0);

    public APrototype(String s) {
        this.s = s;
    }

    public Reliant getReliant() {
        return reliant;
    }

    public void setReliant(Reliant reliant) {
        this.reliant = reliant;
    }

    public void readInfo() {
        System.out.println(s+",reliant info:"+reliant.getI());
    }

    public String getS() {
        return s;
    }

    public void setS(String s) {
        this.s = s;
    }

    @Override
    public Object shallowClone() {
        APrototype ret = new APrototype(s);
        ret.setReliant(reliant);

        return ret;
    }

    @Override
    public Object deepClone() {
        APrototype ret = new APrototype(s);

        ret.setReliant(new Reliant(reliant.getI()));

        return ret;
    }

}

测试一下深浅复制的区别

package prototype;

/**
 * @ClassName: Test
 * @Description: TODO
 * @date 2016年5月19日 上午10:52:24
 *
 * @author leobert.lan
 * @version 1.0
 */
public class Test {

    public static void main(String[] args) {
        Prototype prototype = new APrototype("1");

        APrototype deepCloneTest1 = (APrototype) prototype.deepClone();

        APrototype deepCloneTest2 = (APrototype) prototype.deepClone();

        deepCloneTest1.setS("deepCloneTest1");
        deepCloneTest2.setS("deepCloneTest2");

        deepCloneTest1.getReliant().setI(1);
        deepCloneTest2.getReliant().setI(2);

        deepCloneTest1.readInfo();
        deepCloneTest2.readInfo();

        System.out.println("========================");

        APrototype shallowCloneTest1 = (APrototype) prototype.shallowClone();

        APrototype shallowCloneTest2 = (APrototype) prototype.shallowClone();

        shallowCloneTest1.setS("shallowCloneTest1");
        shallowCloneTest2.setS("shallowCloneTest2");

        shallowCloneTest1.getReliant().setI(1);
        shallowCloneTest2.getReliant().setI(2);

        shallowCloneTest1.readInfo();
        shallowCloneTest2.readInfo();

    }

}

我修改了一下分割,忘了这是markdown

deepCloneTest1,reliant info:1

deepCloneTest2,reliant info:2

!************

shallowCloneTest1,reliant info:2

shallowCloneTest2,reliant info:2


意图

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

适用性

当要实例化的类是在运行时刻指定时,例如,通过动态装载;

或者为了避免创建一个与产品类层次平行的工厂类层次时;

或者当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

另外,深复制往往采用序列化、反序列化手段处理,而且牵涉到一个深度问题,也会有相互依赖的问题,需要注意

单例

单例模式还是用的比较多的,没有必要给demo了

意图

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

适用性

当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。

当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

后记

本想一次性全部写完,但这是奢望啊,这两天已经算比较闲散的了,慢慢来吧,争取分三次写完。demo源码等写完了再上传到下载区吧。

时间: 2024-08-29 04:13:22

[Android基础系列]设计模式(一)的相关文章

[Android基础系列]设计模式(二)

前言 上一篇设计模式一 中,我们只整理了创建型的设计模式,本篇主要看一下结构型的. 正文 结构型包含以下类型: 适配器 Adapter Class/Object 桥接 Bridge 组合 Composite 装饰 Decorator 外观 Facade 享元 Flyweight 代理 Proxy 适配器 个人意见:最适合在工作完成了一部分,但是两套系统接口规范不完全相适的情况下,使用适配器"协调"一下,在从零开始的情况下,尽可能避免接口不适配的情况. demo: 目标 package

Android基础系列合集

四大组件 1.Service Android四大组件-Service Android-远程Service Service 动态更新 UI 2.Activity Android四大组件-Activity Android-Activity启动流程 Android - ANR小结 3.Content Provider Android四大组件-Content Provider android - SQLite 数据库 4.Broadcast Receiver Android四大组件-Broadcast

[Android基础系列]重新审视ContentProvider

前言 上一篇文章梳理了一下Service,这一篇文章梳理一下同为四大组件之一的ContentProvider,也试着使用在线MarkDown编辑器.正常开发中,我们使用ContentProvider较少,大家也不会太过于关注.国内能看到的几篇文章也是比较老旧了,demo中也有一些错误,所以写一篇"像样"的,凑凑数. 正文 概述ContentProvider 依旧去API文档中先拿到官方的概述,并做一点蹩脚的翻译和注解: Content providers are one of the

[Android 基础系列]Service、IntentService和习以为常的误解

前言: 也许是低门槛原因,最初接触Android的人写了很多书.博文,创造了一个邪论:Activity就是弄界面的,Service就是弄后台的,进而将"播放音乐"这种演变为"耗时操作",进而演绎成:"耗时的.长时间运行的都需要使用service".只想说:MDZZ! 原意是想全文自己写,但看了一眼API文档,整理的实在是太好了,所以本文会摘录API的内容并结合重点写一点内容. 正文: Service: API文档中的概述如下: A Service

史上最详细的Android Studio系列教程四--Gradle基础

史上最详细的Android Studio系列教程四--Gradle基础

C#基础系列——委托实现简单设计模式

前言:上一篇介绍了下多线程的相关知识:C#基础系列--多线程的常见用法详解,里面就提到了委托变量.这篇简单介绍下委托的使用.当然啦,园子里面很多介绍委托的文章都会说道:委托和事件的概念就像一道坎,过了这个槛的人,觉得真是太容易了,而没有过去的人每次见到委托和事件就觉得心里发慌.确实这东西就像最开始学C语言的指针一样,令人有一种很纠结的感觉,总觉得要调用一个方法直接调用就行了,为啥非要定义一个委托时执行这个方法呢.其实在C#里面很多的技术都是为了重用和简化代码而生,委托也不例外,很多使用C#多态去

Android基础工具类重构系列一Toast

前言: 一直在考虑写一下Android实际项目中的一些总结,翻看CSDN博客,上一篇已经是一年多曾经. 本系列定位Android基础工具类重构.旨在记录实际项目中经经常使用到的一些工具类,比方Toast.Dialog.动画类,ImageLoader类等等.正在梳理,但发现梳理完再写预计黄花菜都凉了.所以改变策略,边写边梳理. 首先要写的就是这个Toast. 一.说明 作为Android系统提供的基类,Toast是最简单的提示消息类.特点悬浮.跨界面(Activity)特定时间内自己主动销毁. 二

Android Studio系列教程四--Gradle基础

Android Studio系列教程四--Gradle基础 本文为个人原创,欢迎转载,但请务必在明显位置注明出处! 其实很早之前也写了一篇Gradle的基础博客,但是时间很久了,现在Gradle已经更新了很多,所以暂且结合Stduio 1.0正式版与最新的Gradle语法来详细讲解下,小伙伴们直接跟我一步步来学习吧. 什么是Gradle? Gradle是一种依赖管理工具,基于Groovy语言,面向Java应用为主,它抛弃了基于XML的各种繁琐配置,取而代之的是一种基于Groovy的内部领域特定(

Android逆向系列文章— Android基础逆向(6)

本文作者:HAI_ 0×00 前言 不知所以然,请看 Android逆向-Android基础逆向(1) Android逆向-Android基础逆向(2) Android逆向-Android基础逆向(2-2) Android逆向-Android基础逆向(2-3补充篇) Android逆向-Android基础逆向(3) Android逆向-Android基础逆向(4) Android逆向-Android基础逆向(4-2) Android逆向-Android基础逆向(5) 以及java系列: Andr