如果你想成为一名优秀的Android开发工程师,那么设计模式是必须要掌握的。
设计模式六大原则
在通常讲到常用的设计模式之前,首先需要知道设计模式的六大原则:它们分别是
单一职责原则 定义:就一个类而言,应该仅有一个引起它变化的原因
通俗的讲我们不要让一个类承担过多的职责,如果一个类承担过多的职责,就等于把这些职责耦合到一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。开放封闭原则 定义:类 、模块、函数 等应该是可以拓展的,但是不可修改
开放封闭有两个含义 一个是对于拓展是开放的,另一个对于修改是封闭的。里氏替换原则 定义:所有引用基类(父类)的地方必须能够透明的使用其子类对象。
里氏替换原则原则 告诉我们在软件中 将一个基类对象替换成其子类对象,程序不会产生任何错误和异常;反过来则不成立。依赖倒置原则 定义:高层模块不应该依赖低层模块,两者都应该依赖于抽象,抽象不应该依赖于细节,细节应该依赖于抽象
在Java中 ,抽象指接口或者抽象类,两者都是不能直接被实例化的;细节就是指实现类,实现接口或者继承抽象类而产生的就是细节。迪米特原则 定义:一个软件实体应当尽可能少的与其他实体发生相互作用。
在迪米特原则运用到系统设计中时应当注意以下几点:- 在类的划分上,应当尽量创建松耦合的类,类之间的耦合越低,越利于复用,一个处在松耦合中的类一旦被修改,则不会对关联的类造成太大的波及。
- 在类的结构设计上,每个类都应当降低其成员函数和成员变量的访问权限。
- 在对其他类的引用上,一个对象对其他对象的引用应当降到最低。
- 接口隔离原则:定义一个类对另一个类的依赖应该建立在最小的接口上
建立单一接口,不要建立庞大臃肿的接口;尽量细化接口,接口中的方法尽量少,也就是说要为各个类建立专用的接口,不要试图建立一个很庞大的接口提供所有依赖他的类调用。
设计模式分类
GoF 提出的设计模式总共有23种,根据目的准则分类 分三大类 分别是:
1. 创建型设计模式,共5种:单利模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式。
2. 结构性设计模式,共7种:适配器模式,装饰模式,代理模式,外观模式,桥接模式,组合模式,享元模式
3. 行为型设计模式,共11种:策略模式,模板方法模式,观察者模式,迭代器模式,责任链模式,命令模式,备忘录模式,状态模式,访问者模式,中介模式,解释器模式。
创建型设计模式
创建型设计模式 顾名思义 就是与对象的创建有关,它包括 单利模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式。
单例模式
定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
- 单利模式的六种写法
//1,饿汉模式
/**
* 这种方法在类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快,
* 这种方法基于类加载机制,避免了多线程同步问题,在类加载的时候完成了实例化 并没有达到懒加载的效果,如果从始至终未使用过这个实例,则会造成内存的浪费
*/
public class Singleton(){
private static Singleton instance = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return instance;
}
}
// 2,懒汉模式(线程不安全)
/**
* 懒汉模式声明了一个静态对象,在用户第一次调用时初始化,这虽然节约了资源,但第一次加载时
* 需要实例化,反应稍微慢一些,而且在多线程时,不能正常工作。
*/
public class Singleton{
private static Singleton instance;
private Singleton(){
}
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
//3, 懒汉模式(线程安全)
/**
* 这种写法能够在多线程中很好的工作,但是每次调用getInstance方法时都需要进行同步,这会造
* 成不必要的同步开销,而且大部分时候我们是用不到同步的,所以不建议这么写。
*/
public class Singleton{
private static Singleton instance;
private Singleton(){
}
public static synchronized Singleton getInstance(){
if(instance == null ){
instance = new Singleton();
}
return instance;
}
}
//4, 双重检查模式(DCL)
/**
* 这种写法在getInstance 中进行了两次判空;第一次是为了不必要的同步,第二次是在singleton
* 为null 的时候进行实例化,在这里volatile 会或多或少的影响性能,但是考虑到程序的正确性
* 牺牲这点性能还是值得的。
*/
public class Singleton{
private volatile static Singleton instance ;
private Singleton(){
}
public static Singleton getInstance (){
if (instance == null){
synchronized(Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
//5,静态内部类单例模式
/**
* 第一次加载Singleton 类时 并不会初始化 sInstance ,只有在第一次调用getInstance方法的
* 时虚拟机加载 SingletonHolder 并初始化sInstance,这样不仅能确保线程安全,也能保证
* Singleton 类的唯一性,所以 推荐使用静态内部类单例模式。
*/
public class Singleton{
private Singleton(){
}
public static Singleton getInstance (){
return SingletonHolder.sInstance;
}
public static class SingletonHolder{
private static final Singleton sInstance = new Singleton();
}
}
//6, 枚举单例
/**
* 默认枚举实例的创建是线程安全的,并且在任何情况下都是单例。可读性差,一般使用不多。
*/
public enum Singleton{
INSTANCE;
public void doSomething(){
}
}
2.单例模式的使用场景
在一个系统中要求一个类有且仅有一个对象,它的具体使用场景如下:
- 整个 项目需要一个共享访问点或者共享数据。
- 创建一个对象需要耗费的资源过多,比如访问I/O或者数据库资源
- 工具类对象
简单工厂模式
定义:简单工厂模式属于创建型模式,其又被称为静态工厂方法模式,这是由一个工厂对象决定创建出哪一种产品类的实例。
在简单工厂模式中有如下角色
- Factory :工厂类,这是简单工厂模式的核心,它负责实现创建所有实例的内部逻辑,工厂类的创建产品类的方法可以直接被外界直接调用,创建所需的产品对象
- IProduct : 抽象产品类,这是简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
- Product : 具体产品类,这是简单工厂模式的创建目标
1.简单工厂模式的简单实现
(1) 抽象产品类
public abstract class Computer {
/**
* 产品的抽象方法,由具体的产品类实现
*/
public abstract void start();
}
(2) 具体产品类
public class LenovoCompluter extends Computer {
@Override
public void start(){
System.out.println("lenovo start");
}
}
public class HpCompluter extends AbsComputer{
@Override
public void start(){
System.out.println("hp start");
}
}
public class AsusCompluter extends AbsComputer{
@Override
public void start(){
System.out.println("asus start");
}
}
(3) 工厂类
public class ComputerFactory{
public static Computer createComputer(String type){
Computer mComputer = null;
switch(type){
case "lenovo":
mComputer = new LenovoCompluter ();
break;
case "hp":
mComputer = new HpCompluter ();
break;
case "asus":
mComputer = new AsusCompluter ();
break;
}
return mComputer;
}
}
(4) 客户端调用工厂类
public class CreateComputer {
public static void main(String[] args){
ComputerFactory.createComputer("hp").start();
}
}
2.使用简单工厂模式的场景和优缺点
使用场景:
工厂类负责创建的对象比较少
客户只需知道传入工厂的参数,无需关心创建对象的逻辑优点:使用客户跟进参数获得对应的实例,避免了直接实例化类,降低了耦合性。
缺点:可实例化的类型在编译期间已经被确定,如果增加新类型,则需要修改工厂,这违背了开放封闭原则。
工厂方法模式
定义:定义一个用于创建对象的接口,让子类决定实例化哪个类,工厂方法使一个类的实例化延迟到其子类。
在工厂方法中有如下角色:
- Product :抽象产品类
- ConcreteProduct :具体产品类,实现Product接口
- Factory :抽象工厂类,该方法返回一个Product 类型的对象。
- ConcreteFactory : 具体工厂类,返回ConreteProduct 实例。
1.工厂方法模式的简单实现
工厂方法模式的抽象产品类与具体产品类的创建和简单工厂模式是一样的,见上,这里就不赘述了。
(1) 创建抽象工厂
抽象工厂里面有一个createComputer 方法,想生产哪个品牌的计算机就生产哪个品牌的计算机。
public abstract class ComputerFactory{
public abstract <T extends Computer> T createComputer(Class<T> clz);
}
(2) 具体工厂
广达代工厂是一个具体工厂,其继承抽象工厂,通过反射来生产不同厂家的计算机
public class GDComputerFactory extends ComputerFactory{
@Override
public <T extends Computer> T createComputer(Class<T> clz){
Computer computer = null;
String className = clz.getName;
try{
//通过反射来生产不同厂家的计算机
computer = (Computer)Class.forName(className).newInstance();
}catch(Exception e){
e.printStackTrace();
}
return (T)computer;
}
}
(3) 客户端调用
客户端创建了GDComputerFactory,并分别生产了联想 惠普,和华硕计算机
public class Client{
public static void main(String[] args){
ComputerFactory computerFactory = new GDComputerFactory();
LenovoComputer mLenovoComputer = computerFactory.createComputer(LenovoComputer.class);
mLenovoComputer.start();
HpComputer mHpComputer = computerFactory.createComputer(HpComputer.class);
mHpComputer.start();
AsusComputer mAsusComputer = computerFactory.createComputer(AsusComputer.class);
mAsusComputer.start();
}
}
建造者模式
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
在建造者模式中有如下角色:
- Director :导演类,负责安排已有模块的顺序,然后通知Builder 开始建造。
- Builder : 抽象Builder类,规范产品的组建,一般由子类实现。
- ConcreteBuilder : 具体建造者,实现抽象Builder类定义的所有方法,并返回一个组建好的对象。
- Product :产品类
1,建造者模式的简单实现
(1) 创建产品类
public class Computer{
private String mCpu;
private String mMainBoard;
private String mRam;
public void setCpu(String cpu){
this.mCpu = cpu;
}
public void setMainBoard(String mainBoard){
this.mMainBoard = mainBoard;
}
public void setRam(String ram){
this.mRam = ram;
}
}
(2) 创建Builder类来规范产品的组建
public abstract class Builder{
public abstract void buildCpu(String cpu);
public abstract void buildMainBoard(String mainBoard);
public abstract void buildRam(String ram);
public abstract Computer create();
}
商家实现了抽象builder类,MoonComputerBuilder 类来组装计算机
public class MoonComputerBuilder extends Builder{
private Computer mComputer = new Computer();
@Override
public void buildCpu(String cpu){
mComputer.setCpu(cpu);
}
@Override
public void buildMainBoard(String mainBoard){
mComputer.setMainBoard(mainBoard);
}
@Override
public void buildRam(String ram){
mComputer.setRam(ram);
}
@Override
public Computer create(){
return mComputer;
}
}
(3) 用导演类来统一组装过程
public class Director{
Builder mBuild = null;
public Director(Builder builder){
this.mBuild = builder;
}
public Computer CreateComputer(String cpu,String mainBoard,String ram){
this.mBuild.buildMainBoard(mainBoard);
this.mBuild.buildCpu(cpu);
this.mBuild.buildRam(ram);
return mBuild.create();
}
}
(4)客户端调用导演类
public class CreateComputer{
public static void main(String[] args){
Builder mBuilder = new MoonComputerBuilder();
Director mDirector = new Director(mBuilder);
mDirector.createComputer("i7-6700","华秦玩家至最","三星DDR4");
}
}
2, 使用建造者模式的场景及优缺点
- 使用场景:
相同的方法,不同的执行顺序,产生不同的事件结果时
等等~ - 优点:
使用建造者模式时,可以使客户端不必知道产品内部的组成细节
等等~ - 缺点:
产生多余的builder对象及导演类
结构型设计模式
结构型设计模式,是从程序的 结构上解决模式之间的耦合问题,它包括适配器模式,代理模式,装饰模式,外观模式,桥接模式,组合模式,和享元模式
这里主要会介绍 代理模式,装饰模式,外观模式,和享元模式。
代理模式
待续~~~~