如果作为低年级入门的同学学习设计模式是比较困难的,建议先补充基础,积累经验再回过头进行学习设计模式,因为其中的重要性关乎到我们是否能够进阶成为相对优秀的Android工程师,高年级大佬麻烦多多指导。在阅读或者分析源码的时候,或多或少离不开设计模式,下面我只是挑了几个来谈谈我学习的理解。
在分享设计模式之前,我们先了解下设计模式的六大原则:
1.单一职责原则:对于一个类而言,应该仅有一个引起它变化的原因。通俗地理解是不要在Activity中写Bean文件、网络请求处理和Adapter等。
2.开放封闭原则:类、模块、函数等应该是可以拓展,但是不可以修改。在开发中,需求是变化的,如果有新的需求,我们就要重新把类改一遍显然是很爆炸的,所有进来通过扩展的方式实现
3.迪米特原则:一个软件应当尽可能少地和其他实体发生相互作用。
4.接口隔离原则:一个类对另一个类的依赖应该建立在最小的接口上,接口的负责化要适度
5.依赖倒置原则:高层模块不应该依赖底层模块,两者都应该依赖于抽象。抽象不应该依赖细节,细节应该依赖与抽象。读起来很拗口,在Java中,抽象是指接口和抽象类;细节是实现类;高层模块就是调用者,底层模块就是具体的实现类,我的理解是类跟类之间的依赖通过抽象产生的。
6.里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象。
下面进入设计模式的话题,包括了:
创造型设计模式:单例模式、建造者模式(ps:简单工厂模式和抽象工厂模式理解的还不是很好,所以先不做分享)、结构型模式中的享元模式和行为型设计模式中的策略模式、观察者模式
一、单例模式:保证一个类仅有一个实例,并且提供一个可以访问的方法
/**
* 6种单例模式写法
* Created by XQM on 2018/5/13.
*/
//第一种,饿汉式.基于类加载机制,在类加载的时候就完成实例化,如果至始至终没有使用到该类会造成内存浪费
public class SingleDemo {
private static SingleDemo instance = new SingleDemo();
public static SingleDemo getInstance(){
return instance;
}
}
//第二种,懒汉式,第一次加载时需要实例化,反应慢,在多线程并发不能保证单例
public class SingleDemo{
private static SingleDemo instance;
public static SingleDemo getInstance() {
if (instance == null){
instance = new SingleDemo();
}
return instance;
}
}
//每次调用都需要同步,造成不必要的同步开销
public class SingleDemo{
private static SingleDemo instance;
public static synchronized SingleDemo getInstance() {
if (instance == null){
instance = new SingleDemo();
}
return instance;
}
}
//双重检查模式DCL,在某些情况下会失效
public class SingleDemo{
private static SingleDemo instance;
public static SingleDemo getInstance() {
if (instance == null){
synchronized (SingleDemo.class){
if (instance == null){
instance = new SingleDemo();
}
}
}
return instance;
}
}
//静态内部类单例模式,第一次类加载的时候并不会初始化instance,
//当且仅当调用了getInstance()时JVM加载SingleDemoHolder初始化instance,
//所以保证了线程安全和单例,推荐使用
public class SingleDemo{
public static SingleDemo getInstance() {
return SingleDemoHolder.instance;
}
private static class SingleDemoHolder{
private static final SingleDemo instance = new SingleDemo();
}
}
/**
* 枚举单例
*/
public enum SingleDemo{
INSTANCE;
private void doSomThing(){
}
}
补充下JVM对内部类的加载顺序
//静态内部类单例模式,推荐使用
public class SingleDemo{
public static SingleDemo getInstance() {
return SingleDemoHolder.instance;
}
//类静态属性
public static SingleDemo testOut = new SingleDemo(1);
static {
System.out.println("调用静态代码块:Static function");
}
private static class SingleDemoHolder{
static {
System.out.println("调用匿名内部类:Inner Static");
}
private static final SingleDemo instance = new SingleDemo(3);
}
public SingleDemo(int i) {
switch (i){
case 1:
System.out.println("调用静态属性: " +" Construct! "+i);
break;
case 2:
System.out.println("调用自身构造方法: " +" Construct! "+i);
break;
case 3:
System.out.println("调用匿名内部类静态属性: " +" Construct! "+i);
break;
}
}
}
//主函数测试,根据下面的结果发现,初始化的时候,静态块和静态变量是按顺序的,内部类按需调用
public class BuilderClient {
public static void main(String[] args){
SingleDemo singleDemo = new SingleDemo(2);
SingleDemo.getInstance();
}
}
二、建造者模式:用来创建复杂对象的模式,将其部件解耦。通常Android中的Dialog或者EventBus使用的时候会碰到。
/**
* 定义产品
* Created by XQM on 2018/5/13.
*/
public class Computer {
private String mCpu;
private String mMain;
private String mCard;
private String mRam;
public String getmCpu() {
return mCpu;
}
public void setmCpu(String mCpu) {
this.mCpu = mCpu;
}
public String getmMain() {
return mMain;
}
public void setmMain(String mMain) {
this.mMain = mMain;
}
public String getmCard() {
return mCard;
}
public void setmCard(String mCard) {
this.mCard = mCard;
}
public String getmRam() {
return mRam;
}
public void setmRam(String mRam) {
this.mRam = mRam;
}
@Override
public String toString() {
return "Computer{" +
"mCpu='" + mCpu + '\'' +
", mMain='" + mMain + '\'' +
", mCard='" + mCard + '\'' +
", mRam='" + mRam + '\'' +
'}';
}
}
/**
* 抽象产品的组建
* Created by XQM on 2018/5/13.
*/
public abstract class Builder {
public abstract void buildCpu(String cpu);
public abstract void buildMainboard(String main_board);
public abstract void buildGraphicsCard(String graphics_card);
public abstract void buildRam(String ram);
public abstract Computer create();
}
/**
* 真正的建造者,实现build的方法,然后返回组建好的对象
* Created by XQM on 2018/5/13.
*/
public class BuildComputer extends Builder {
private Computer computer = new Computer();
@Override
public void buildCpu(String cpu) {
computer.setmCpu(cpu);
}
@Override
public void buildMainboard(String main_board) {
computer.setmMain(main_board);
}
@Override
public void buildGraphicsCard(String graphics_card) {
computer.setmCard(graphics_card);
}
@Override
public void buildRam(String ram) {
computer.setmRam(ram);
}
@Override
public Computer create() {
return computer;
}
}
public class Assembly {
Builder builder;
public Assembly(Builder builder) {
this.builder = builder;
}
public Computer CreateComputer(String cpu ,String main,String card,String ram){
builder.buildCpu(cpu);
builder.buildMainboard(main);
builder.buildRam(ram);
builder.buildGraphicsCard(card);
return builder.create();
}
}
//测试主类
public class BuilderClient {
public static void main(String[] args){
Builder builder = new BuildComputer();
Assembly assembly = new Assembly(builder);
Computer sc = assembly.CreateComputer("i7-6700","联想","890","金士顿DDR4");
System.out.println(sc.toString());
}
}
三、享元模式:是池技术的重要实现方式,可以减少应用程序创建对象,降低产生OOM风险,提高程序的性能。
/**
* 抽象享元角色
* Created by XQM on 2018/5/13.
*/
public interface IGoods {
void showGoodsPrice(String name);
}
/**
* 具体享元角色,实现抽象享元角色
* Created by XQM on 2018/5/13.
*/
public class Goods implements IGoods {
private String name;//名称,内部状态
private String attribute;//属性,外部状态
public Goods(String name) {
this.name = name;
}
@Override
public void showGoodsPrice(String attribute) {
if (attribute.equals("红色")){
System.out.println("有货,价格是:8974元");
}else {
System.out.println("有货,价格是:8974元");
}
}
}
/**
* 享元工厂用来创建具体的享元角色,通过map来缓存对象
* 如果系统存在大量的相似对象或者缓存池的场景可以使用
* Created by XQM on 2018/5/13.
*/
public class GoodsFactory {
private static Map goodsMap = new HashMap<>();
public static Goods getGoods(String name){
if (goodsMap.containsKey(name)){
System.out.println("缓存中找到商品,key:"+name);
return goodsMap.get(name);
}else {
Goods good = new Goods(name);
goodsMap.put(name,good);
System.out.println("创建商品,key:"+name);
return good;
}
}
}
/**
*测试类
* 享元模式缓存对象,避免OOM
* Created by XQM on 2018/5/13.
*/
public class FlywightClient {
public static void main(String[] args){
Goods goods = GoodsFactory.getGoods("华为3e");
goods.showGoodsPrice("红色");
Goods goods1 = GoodsFactory.getGoods("华为3e");
goods1.showGoodsPrice("幻影黑");
Goods goods2 = GoodsFactory.getGoods("华为9");
goods2.showGoodsPrice("幻影黑");
}
}
四、策略模式:定义一系列的算法,把算法封装起来,并且是它们可以相互替换,使得算法可以独立于使用它的客户而独立变化。比如代码有很多if…else或者case,会变得比较臃肿,维护成本也比较高,违背开放封闭原则,通过策略模式就可以简化。
/**
* 定义一个程序开发的接口
* 抽象策略角色
* Created by XQM on 2018/5/13.
*/
public interface IDevelopStrategy {
void develop();
}
/**
* 开发
* Created by XQM on 2018/5/13.
*/
public class APPStrategy implements IDevelopStrategy {
@Override
public void develop() {
System.out.println("产品发话了,需要开发APP");
}
}
/**
* 具体的策略
* Created by XQM on 2018/5/13.
*/
public class WebSiteStrategy implements IDevelopStrategy {
@Override
public void develop() {
System.out.println("产品发话了,需要开发网站");
}
}
/**
* 上下文角色的构造方法根据传递进来不同的具体策略来调用不用的develop()
* 屏蔽调用者对策略的直接访问,启动承上启下作用
* Created by XQM on 2018/5/13.
*/
public class Context {
private IDevelopStrategy strategy;
public Context(IDevelopStrategy strategy) {
this.strategy = strategy;
}
public void develop(){
strategy.develop();
}
}
/**
* 每一个策略都是一个类,复用性小
* 上层模块必须知道有哪些策略才可以使用
* Created by XQM on 2018/5/13.
*/
public class StrategyClient {
public static void main(String[] args){
Context context;
//开发APP
context = new Context(new APPStrategy());
context.develop();
//开发网站
context = new Context(new WebSiteStrategy());
context.develop();
}
}
五、观察者模式:定义对象间一对多的依赖关系,每当一个对象改变状态时,则所有依赖于它的对象都会得到通知并且被自动更新。常见运用在发布-订阅事件总线。
/**
* 把所有的观察者对象保存在一个集合中,其中每一个主题可以有任意数量的观察者,可以想象为公众号
* Created by XQM on 2018/5/13.
*/
public interface ObservedSubject {
/**
* 增加观察者
* @param observer
*/
void add(Observer observer);
/**
* 删除观察者
* @param observer
*/
void delete(Observer observer);
/**
* 通知更新
* @param message
*/
void notify(String message);
}
/**
* 抽象被观察者的实现类,实现添加、删除和通知观察者的方法
* Created by XQM on 2018/5/13.
*/
public class SubcriptionSubject implements ObservedSubject {
private List subscriberUsers = new ArrayList();
@Override
public void add(Observer oberver) {
subscriberUsers.add(oberver);
}
@Override
public void delete(Observer observer) {
subscriberUsers.remove(observer);
}
@Override
public void notify(String message) {
for (Observer observer:subscriberUsers){
observer.update(message);
}
}
}
/**
* 抽象观察者
* Created by XQM on 2018/5/13.
*/
public interface Observer {
void update(String message);
}
/**
* 具体观察者
* Created by XQM on 2018/5/13.
*/
public class SubscriberUser implements Observer {
private String name;
public SubscriberUser(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name+"更新了:"+message);
}
}
/**
* 优点:观察者和被观察者之间是抽象耦合,容易扩展
* 缺点:在Java中消息的通知一般是按照顺序的,如果每个观察者造成卡顿,会影响整体的效率,采用异步解决
* Created by XQM on 2018/5/13.
*/
public class ObserverClient {
public static void main(String[] args){
SubcriptionSubject subcriptionSubject = new SubcriptionSubject();
SubscriberUser user1 = new SubscriberUser("下雨了");
SubscriberUser user2 = new SubscriberUser("下雪了");
SubscriberUser user3 = new SubscriberUser("落花了");
//注册订阅
subcriptionSubject.add(user1);
subcriptionSubject.add(user2);
subcriptionSubject.add(user3);
//发送更新给订阅者
subcriptionSubject.notify("不一样的博客更新了");
}
import java.util.Observable;
/**
* 继承Observable类(被观察者发送消息),notifyObservers发送通知
* Created by XQM on 2018/3/22.
*/
public class Gamedaily extends Observable {
public void postNewArticle(String content){
//内容改变
setChanged();
//通知所有订阅者改变内容
notifyObservers(content);
}
}
import java.util.Observable;
import java.util.Observer;
/**
* 定义观察者,继承observer接口,实现update方法
* Created by XQM on 2018/3/22.
*/
public class User implements Observer{
public String name;
public User(String name) {
this.name = name;
}
@Override
public void update(Observable observable, Object o) {
System.out.println("Hi "+name +",公众号更新了内容:"+o);
}
}
/**
* Created by XQM on 2018/3/22.
*/
public class Client {
public static void main(String[] args){
Gamedaily gamedaily = new Gamedaily();
User user0 = new User("user0");
User user1 = new User("user1");
User user2 = new User("user2");
gamedaily.addObserver(user0);
gamedaily.addObserver(user1);
gamedaily.addObserver(user2);
gamedaily.postNewArticle("有新文章更新了");
}
}