设计模式(上)

设计模式是指控件在页面设计器中呈现时运行的代码。设计模式使人们可以更加简单方便地复用成功的设计和体系结构。将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。

设计模式有23种,在编程规范和体系结构设计中被广泛采用,其中最常用的有以下10种,本为以简单的例子介绍设计模式的核心内容并通过android项目开发过程深入介绍设计模式在其中的作用。笔者水平有限,如有错误还请联系改正,谢谢。以上,笔者默认读者有一定的Java基础,对纯小白不太友好,若是有一定Android基础阅读更佳。

以下式设计模式的分类汇总,根据使用频度的不同,笔者将部分比较重要或使用频度更高的部分特别标注出来,并详细展开。
tips:不知为何,图片看起来好模糊,可以点开查看原图会好一些,见谅。

image.png

这里不得不提一下设计模式的设计原则,也正得益于这些设计原则,在程序健壮、高效、可复用方面有章可循

  • 1、开闭原则(Open Close Principle)
    对扩展开放,对修改关闭。在程序需要进行拓展的时候,为了使程序的扩展性好,易于维护和升级,不能去修改原有的代码,使用接口和抽象类实现一个热插拔的效果。

  • 2、里氏代换原则(Liskov Substitution Principle)
    任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,里氏代换原则是对实现抽象化的具体步骤的规范。

  • 3、依赖倒转原则(Dependence Inversion Principle)
    针对接口编程,依赖于抽象而不依赖于具体

  • 4、接口隔离原则(Interface Segregation Principle)
    使用多个隔离的接口,比使用单个接口要好。降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。

  • 5、迪米特法则,又称最少知道原则(Demeter Principle)
    一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立

  • 6、合成复用原则(Composite Reuse Principle)
    尽量使用合成/聚合的方式,而不是使用继承

单例模式

单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局的访问点。

单例模式要点

  • 私有的构造方法
  • 指向实例的私有静态引用
  • 获取实例对象的公有静态方法
饿汉模式(非线程安全)类在被Java虚拟机加载过程中直接创建
public class SingleTon {
    private SingleTon(){}//私有化构造函数
    private static final SingleTon singleTon=new SingleTon();
    public static SingleTon getInstance(){
        return singleTon;
    }
}
懒汉模式(非线程安全)类只有在被实例化时才被创建
public class SingleTon {
    private SingleTon() {}//私有化构造函数
    private static SingleTon singleTon;
    public static SingleTon getInstance() {
        if (singleTon == null)
            singleTon = new SingleTon();
        return singleTon;
    }
}
双重线程锁检查单例(线程安全)
public class SingleTon {
    private SingleTon() {}//私有化构造函数
    private static volatile SingleTon singleTon;
    public static SingleTon getInstance() {
        if (singleTon == null){
            synchronized (SingleTon.class){
                SingleTon st=singleTon;
                if (st == null) {
                    st=new SingleTon();
                    singleTon=st;
                }
            }
        }
        return singleTon;
    }
}
枚举单例
public enum SingleTon{
    Instance;
}

简单工厂模式

工厂方法模式(Factory Method Pattern):定义一个创建对象的接口,但由子类决定要实例化的类是哪一个工厂方法,让类把实例化推迟到子类。

  • 第一步
    创建一个抽象的Vehicle类,注意其中的抽象方法public abstract void assemble();
public abstract class Vehicle {
    protected String name;
    public abstract void assemble();
    public void constructFrame(){
        System.out.println("construct the frame of vehicle");
    }
    public void assembleTyre(){
        System.out.println("assemble tyres");
    }
    public void attachBody(){
        System.out.println("attach body");
    }
    public void setName(String name) {
        this.name = name;
    }
}
  • 第二步
    创建两个类CarTruck继承自Vehicle类并覆写上面定义的public abstract void assemble()方法

Car.java

public class Car extends Vehicle{
    @Override
    public void assemble() {
        super.setName("Car");
        System.out.println("assemble "+name);
    }
}

Truck.java

public class Truck extends Vehicle {
    @Override
    public void assemble() {
        super.setName("Truck");
        System.out.println("assemble "+name);
    }
}

代码很简单,而且也不长,即使是入门水平,看懂也没什么问题,不多废话。

  • 第三步
    创建VehicleFactory工厂方法类,该类只包含一个createVehicle()方法,用于创建Vehicle;
public class VehicleFactory {
    public Vehicle createVehicle(String vehicleType){
        Vehicle vehicle=null;
        if (vehicleType.equals("Truck"))
            vehicle=new Truck();
        else if(vehicleType.equals("Car"))
            vehicle=new Car();
        vehicle.constructFrame();
        vehicle.assembleTyre();
        vehicle.attachBody();
        return vehicle;
    }
}

至此我们的简单工厂就完成了,下面我们测试一下

public class Main {
    public static void main(String[] args) {
        VehicleFactory vehicleFactory=new VehicleFactory();
        Vehicle vehicle=vehicleFactory.createVehicle("Car");
        vehicle.assemble();
    }
}

运行结果如下:

D:\installdirectory\jdk\bin\java 
construct the frame of vehicle
assemble tyres
attach body
assemble Car

Process finished with exit code 0

观察者模式

观察者模式(Observer Pattern):定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他们的所有依赖者都会收到通知并自动更新。

这里我们使用Android开发中的一个实例来说明观察者模式即:Android的广播通信BroadcastReceiver,这里我们会略去Android相关知识,仅仅关注核心代码;

  • 第一步
    定义一个检测网络变化的接口,一旦网络状态发生变化,就调用notifyNetWorkStatusChange()方法通知注册用户更新网络状态。
  • registerObserver()注册通知
  • unRegisterObserver()取消通知注册
public interface NetWorkDetectiveManager {
    void registerObserver(NetWorkStatusChange netWorkStatusChange);
    void unRegisterObserver(NetWorkStatusChange netWorkStatusChange);
    void notifyNetWorkStatusChange();
}

然后定义一个接口用于更新网络状态,这里我们直接忽略参数,只关注onNetWorkChange()方法本身。

public interface NetWorkStatusChange {
    void onNetWorkChange(Boolean wifiStatus,Boolean dataStatus);
}
  • 第二步

定义一个广播接收器实现NetWorkDetectiveManager接口的三个方法;

这里我们只关注一下标注的几个方法

  • private ArrayList<NetWorkStatusChange> notifyList=new ArrayList<>();这里定义了一个ArrayList<NetWorkStatusChange>集合用于存放注册监听的类对象。
  • registerObserver() notifyList.add(netWorkStatusChange);注册的过程其实就是向集合中添加元素的过程。
  • unRegisterObserver()notifyList.remove(netWorkStatusChange)
    同样,解注册就是将元素从集合中移除.
    -notifyNetWorkStatusChange()最后我们通知注册通知的所有元素,网络状态发生了改变,(通过遍历集合中的元素实现)
public class NetWorkDetectiveReceiver 
extends BroadcastReceiver implements NetWorkDetectiveManager{
    private ArrayList<NetWorkStatusChange> notifyList=new ArrayList<>();
    private boolean wifiStaus=false;
    private boolean dataStaus=false;
    @Override
    public void onReceive(Context context, Intent intent) {
         ···
        if (wifiNetworkInfo.isConnected() && !dataNetworkInfo.isConnected()) {
                wifiStaus=true;
                dataStaus=false;
                notifyNetWorkStatusChange();
         }
          ···
    }

    @Override
    public void registerObserver(NetWorkStatusChange netWorkStatusChange) {
        notifyList.add(netWorkStatusChange);
    }

    @Override
    public void unRegisterObserver(NetWorkStatusChange netWorkStatusChange) {
        if(notifyList.indexOf(netWorkStatusChange)>=0){
            notifyList.remove(netWorkStatusChange);
        }
    }

    @Override
    public void notifyNetWorkStatusChange() {
        for (int i=0;i<notifyList.size();i++){
            NetWorkStatusChange netWorkStatusChange=notifyList.get(i);
            netWorkStatusChange.onNetWorkChange(true,true);
        }
    }
}
  • 第三步
    更新数据的部分已经完成,一下是接收数据的部分,这里我们需要是实现NetWorkStatusChange接口,在onNetWorkChange()方法里我们可以实现自己的处理逻辑。至此,观察者模式的实例已经结束了,思路很简单,就是通过接口实现注册通知进行数据更新。此外,Android的广播通信设计模式同样是观察者模式,我们可以通过静态注册或是动态注册的方法注册广播,当系统发送广播时,我们就会收到相应的数据信息并及时更新app数据。
public class ContentAdapter 
extends BaseAdapter implements NetWorkStatusChange {
    ···
    @Override
    public void onNetWorkChange(Boolean wifiStatus, Boolean dataStatus) {
        //to-do 
        //这里我们可以写一些相关的处理逻辑
    }
    ···
}

装饰者模式

装饰者模(Decorate Pattern):式动态地将责任附加到对象上,装饰者提供比继承更加有弹性的替代方案。
为了便于理解,我们暂且不讨论该模式怎么实现,我们先看一下应用的小例子:

public class DecoratorPatterners {
    public static void main(String[] args) {
        Base base=new Frame();
        base=new DectoratorA(base);
        base=new DectoratorB(base);
    }
}

上面这段代码定义了三个类分别是

  • Base所有类的父类
  • Frame被装饰者基类
  • DecoratorA 装饰者A
  • DecoratorB装饰者B
    要想实现上述base=new DectoratorA(base);的效果,很显然,Frame类和Decorator类都是继承自同一个类Base,如此很容易推出,我们需要创建一个抽象基类Base,下面来看代码,这里我简单定义了一些方法和属性,便于继承和累加。
  • 第一步
    Base基类其实就是一个简单的POJO类,定义了两个属性namelength以及他们的get和set方法,这里我们留意一下最后一个抽象方法public abstract float totalLength();,后面会提及.
public abstract class Base {
    public String name="";
    private int length=0;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

    public abstract float totalLength();
}

而后定义一个被装饰的类Frame继承自Base类并覆写抽象方法totalLength();用于返回当前对象长度。

public class Frame extends Base{
    @Override
    public float totalLength() {
        return super.getLength();
    }
}
  • 第二步
    开始创建装饰者类A,B,为了减少文件数量,我将Decorator和另外两个类放在同一个文件中,这里实现了传如Base基类的过程,之后调用totalLength()方法计算被装饰后的总长度,而子类DecoratorADecoratorB两个类只需要调用父类的构造函数并设置自身长度就可以了;至此,装饰者模式已经创建完毕,我们直接使用一开始的小例子就可以直接执行了。
//Decorator.java
public class Decorator extends Base{
    private Base Obj;
    public Decorator(Base obj) {
        Obj = obj;
    }
    @Override
    public float totalLength() {
        return super.getLength()+Obj.totalLength();
    }
}
class DecoratorA extends Decorator{
    public DecoratorA(Base obj) {
        super(obj);
        super.setLength(3);
    }
}
class DecoratorB extends Decorator{
    public DecoratorB(Base obj) {
        super(obj);
        super.setLength(2);
    }
}

模板方法模式

模板方法模式:(Template Method Pattern)在一个方法中定义一个算法框架,而将一些步骤延迟到子类中,模板方法可以使子类在不改变算法结构的情况下重新定义算法中的某些步骤。
我们假定组装一辆车需要四个步骤,其中assembleTyre()paint()是相同的,我们在父类中定义好,另外两个写成抽象方法,在子类中实现。

  • constructFrame();
  • assembleTyre();
  • attachBody();
  • paint();
  • 第一步
    创建抽象类,定义汽车组装过程为final,
public abstract class Vehicle {
    public final void assembleVehicle(){
        constructFrame();
        assembleTyre();
        attachBody();
        paint();
    }

    public abstract void constructFrame();
    public void assembleTyre() {
        System.out.println("assemble vehicle tyre");
    }
    public abstract void attachBody();
    public void paint() {
        System.out.println("paint vehicle body");
    }
}
  • 第二步
    定义两个不同类型的车CarTruck继承自Vehicle,实现父类未完成抽象方法,至此,模板方法模式已经完成了,怎么样,是不是很简单呢?下面我们就可以写主函数做测试了,
//Car.java
public class Car extends Vehicle{
    @Override
    public void constructFrame() {
        System.out.println("construct car frame");
    }

    @Override
    public void attachBody() {
        System.out.println("attach car body");
    }
}
//Truck.java
public class Truck extends Vehicle{
    @Override
    public void constructFrame() {
        System.out.println("construct truck frame");
    }

    @Override
    public void attachBody() {
        System.out.println("attach truck body");
    }
}

测试代码比较简单,不多赘述。

public class Main {
    public static void main(String[] args) {
        System.out.println("##########################Car");
        Car car=new Car();
        car.assembleVehicle();
        System.out.println("##########################Truck");
        Truck truck=new Truck();
        truck.assembleVehicle();
    }
}

输出结果如下

D:\installdirectory\jdk\bin\java
##########################Car
construct car frame
assemble vehicle tyre
attach car body
paint vehicle body
##########################Truck
construct truck frame
assemble vehicle tyre
attach truck body
paint vehicle body

Process finished with exit code 0

未完待续。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,490评论 18 139
  • 参考资料:菜鸟教程之设计模式 设计模式概述 设计模式(Design pattern)代表了最佳的实践,通常被有经验...
    Steven1997阅读 1,159评论 1 12
  • Clojure 设计模式 Design Patterns 译自 Clojure Design PatternsAu...
    BlindingDark阅读 2,335评论 1 6
  • 今日又大风。小朋友早晨起床时说,隔壁邻居回来了,他们挠了一晚上墙,甚乐。我告诉她说肯定是风,昨天晚上我睡前就听到了...
    清越泠泠阅读 183评论 0 0
  • 昨天发表了一条说说,召唤小伙伴们一起写作,欣慰的是得到了朋友的支持,他们也表示会响应。对于时常感到孤独的我来说,这...
    残剑阅读 234评论 2 1