设计模式

设计模式

介绍常用的设计模式,突破代码约束,从设计模式开始。

设计模式可以分为创建型 结构型 和行为型
创建型主要用于描述如何创建对象。结构性主要用于如何实现类或对象的组合 行为型主要用于描述类或是对象如何交互。

创建型:单例模式 简单工厂模式 工厂模式 工厂方法模式 原型模式 建筑者模式

机构型:适配器模式 桥接模式 组合模式 装饰模式 外观模式 享元模式 代理模式

行为型:解释器模式 职责模式 ,命令模式 迭代器模式 观察者模式 状态模式 策略模式 模板模式 模板方法模式 访问者模式 中介者模式

反射

反射的编程特点:大大的提高了稳定框架的能力。具体变现在,当新增加功能的时候,仅仅增加相应的功能类,而框架调用可能不需要发生变化。
抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。

public class ReflectionTest {

    public static void setObjectColor(Object obj) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAcces***ception, InvocationTargetException{
        Class cls = obj.getClass();
        //获得类的私有方法
        Method method = cls.getDeclaredMethod("privateMethod", null);
        method.setAccessible(true); //没有设置就会报错
        //调用该方法
        method.invoke(obj, null);
    }
    public static void main(String args[]) throws SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAcces***ception, InvocationTargetException{

        setObjectColor(new MyTest());
    }

class MyTest{


    public void setMyTest(){
        System.out.println("setMyTest");
    }
    /**
     类的私有方法
     **/
    private void privateMethod(){
        System.out.println("调用了 private Method");
    }

}

单例模式

不管new多少次仅仅创建这个类的一个实例,比如日志记录的管理类 数据库的连接池 日志管理 Runtime类的实现
查看方法执行耗费的系统内存

Runtime  runtime  = new Runtime.getRuntime();
long start = runtime.freeMemory();
//do something
long end = runtime.freeMemory();
System.out.println(end - start);

单例模式的实现方法其实十分的简单,就是定义一个该类的静态变量,然后再定义一个获取该静态变量的静态方法。

单例模式需要注意的是需要将构造函数定义为private 防止通过构造函数获取该类的实例。
饥饿式单例模式(单线程中使用)

public class Singleton
{
    private static Singleton instance = new Singleton();
    private Singleton()
    {
    }
public static Singleton getInstance()
    {
    return instance;
    }
}
// 单例模式的另一种展示方式

public class Singleton
{
    private static Singleton instance = new Singleton();
    private Singleton()
    {
    }
public static Singleton getInstance()
    {
        if(instance == null)
        {
            instance = new Singleton();
        }
    }
}    

// 双检测锁机制的单例模式
//在多线程中使用 if(instance == null)就会出问题
public class Singleton
{
    private static Singleton instance = new Singleton();
    private Singleton()
    {
    }
public static synchronize Singleton getInstance()
    {
        if(instance == null)
        {
            instance = new Singleton();
        }
    }
}    
//这种写法也有问题,没运行一个单例就会进行同步,效率非常低

public class Singleton
{
    private static Singleton instance = new Singleton();
    private Singleton()
    {
    }
public static Singleton getInstance()
    {
        if(instance == null)
        {
            synchronize (Singleton.class)
            instance = new Singleton();
        }
    }
}    
//双检测锁机制
public class Singleton
{
    private static Singleton instance = new Singleton();
    private Singleton()
    {
    }
public static Singleton getInstance()
    {
        if(instance == null)
        {
            synchronize (Singleton.class)
            {
                if(instance == null)
                instance = new Singleton();
            }
        }
    }
return instance;
}    

工厂模式

对象的创建和使用分离,就是简单的工厂模式srping采用的是工厂模式的道理

工厂模式举例:

public class Product
{
    private double num;
    private double price;
    private double total;
    public double getNum()
    {
        return num;
    }
    public double getPrice()
    {
        return price;
    }
    public void setPrice(double price)
    {
        this.price = price;
    }
}
//这样我们在man函数里调用的时候就是:
  Product pro =new Product();
  pro.setPrice(12);
  pro.setNum(234);

如果这个时候我们增加一个折扣率,我们就需要在调用的时候写很多垃圾代码:pro.setPrice(12) * 0.1 等
这个时候我们考虑使用工厂模式 如下

public class Product
{
    private double num;
    private double price;
    private double total;
    public double getNum()
    {
        return num;
    }
    public double getPrice()
    {
        return price;
    }    
    private double rebate;
    public double getRebate()
    {
         return rebate;
    }
    public double getToal()
    {
        total = num * price *rebate;
        return total;
    }
    public void setPrice(double price)
    {
        this.price = price;
    }
}

抽取出来的工厂代码

public class SimpleFactory
{
    public static double getTotal(double num, double price, double rebate)
    {
        Product pro = new Product();
        pro.setNum(0);
        pro.setPrice(0);
        return pro.getTotal();
    }
}
客户调用
 System.out.println(SimpleFactory.getTotal(...));   

原型模式

如请假单一样 需要很多个请假单,但是每个都一样 仅仅是地址不一样,也就是说如果有一个对象,已经包含了一些初始值,当需要一个和该对象完全相同的新对象。在java中可以很直接将该对象赋值给新对象,但是以为内java地址传递,因此如果修改的新的对象的值,则原来的值也会被修改,如果不希望修改就需要原型模型。
原型模型就是普通的get set方法 然后以对象的形式调用 这样就能够通过get和set修改对象的值和对象的属性
如果将新的对象的值改变后 原来对象的值也会改变,这样就不能达到预期的结果,我们可以通过在get和set的方法中写这样一段代码

public  Object clone
[
Object obj = null;
try
{
obj = super.clone;
}
catch(CloneNotSupportedException ex)
{
System.out.println(ex);
}
return obj;
}
原型模型的实现就是通过一个原型对象来表明要 创建的对象类型,然后用复制这个原型对象的方法来创建更多类型的对象

创建者模式

一般用于构造函数,参数过多的情况。
创建者模式就是将一个复杂的对象的构建与它表示分离,使同样的构建过程可以创建不同的表示,而且客户不用知道对象的构建细节。当系统创建一组复杂的对象,而且这个复杂的对象组装起来比较麻烦时,就可以使用创建者模式了。
就像提到的翻译得的例子,如果翻译器需要加入更多的功能,如果都放到工厂中就显得不是很合理,如果能够将这些功能匹配单独抽取出来,放到一个单独的组装类中,就实现了类的单一职能,这就是创建者模式

创建者模式设计4个关键角色: 产品 抽象生成器 具体生成器 指挥者

适配器模式

当一个系统使用另一个外部提供的接口,而这个接口与目前系统使用的接口不兼容,就需要使用适配器模式,适配器模式就是将一个系统的接口转换成另外一种形式。
适配器模式的意图在于,使用不同的接口类所提供的服务Wie客户端提供它所期望的接口。

public  interface Target
{
    public String Method1(String s1);
    public String Method2(String s1);
    public String Method3(String s1);
    public String Method4(String s1);
    public String Method5(String s1);
    public String Method6(String s1);
}

当一个用户需要使用Method中一个一个方法的时候需要复写其他的所有方法,这样就给用户带了了极大的不方便。这个时候我们考虑使用适配器模式‘
我们首先建立一个类来实现接口的所有的方法

public class TargetImpl implements Target]
{
            public String Meshod1(String si)
{

适配器模式就是将一个系统的接口转换成另一种形式,从而使原来不能直接用的接口,变得可以调用
Junit中使用了适配器模式

门面模式

又成为外观模式,这种模式实现了子模块与客户端的松耦合关系,从而屏蔽了子模块内部的实现细节。
在java框架中有很多的地方读取了XML文件,如果在程序中写了读取xml的代码,那么程序就显得十分的凌乱,此时需要读取xml的代码抽取出来,形成统一的接口,这就是门面模式的统一应用。
门面模式就是为子系统对外提供一组接口提供一个统一的界面,使得其他系统对该系统的访问都通过这一个统一的界面完成。
spring中也大量的使用了门面模式。
一般需要配置或是属性文件的都是门面模式的体现。

代理模式

代理模式就是给一个对象提供一个代理对象,由这个代理对象控制对源对象的引用,使得代理类在客户端和源对象之间起到一个代理的作用,,一般情况下,在开发中需要对一个类或者方法进行额外处理的时候,就需要使用代理模式。
代理模式能够很好的将直接关联的类进行解耦合。

合成模式

又叫做树形模式,就是把部分和和整体的关系用树结构来表示,使得客户端对单个对象和组合对象的使用具有一致性。
如文件夹的复制

享元模式

在编写程序的时候,如果不采用单例模式就会new很多的对象,这对于系统需要使用大量的重复对象,而这些对象要消耗很大的资源的时候,就需要采用享元模式
我们通过一个十分简单的例子看看这个模式的应用

String  str1 = "test";
String  str2 = "test";
System.out.println(str1 == str2);

结果会输出true 也就是str1 和str2 指向相同的单元,这就是享元模式的体现

装饰模式

有时候开发人员会使用继承来拓展对象的功能,用户的需求是多变得,也就是造成使用继承会造成代码的大范围移动,其实拓展对相爱了的功能,采用组合比继承要好的多。这就是我们要说的装饰模式。
我们来看一段实例的代码

public  class Cash
{
    public double getCash(String procuct)
    {
        return 10;
    }
}

我们主方法中需要
Cash cash =new Cash();
cash.getCash("sdf");
来获得对象的价格。
如果要进行打折

public class RebateCash extends Cash
{
public double getCash(String product)
{
    return super.getCash(product) * 0.1;
}
}

然后修改客户端的调用
如果再减少一块钱呢?该如何解决呢 再写一个继承类 是不是让继承的关系越来越复杂

下面我们用装饰模式来解决这个问题

public interface Cash
{
public double getCash(String product);
}
public class CashImpl implements Cash
{
    public double getCash(String product)
{
return 10;
}


Cash cash = new CashImpl();
cash.getCash("test");
public class CashDecorator implements Cash
{
    private Cash cash;
 public CashDecorator(Cash cash)
 {
        this.cash = cash;
 }
 public double getCash(String product)
 {
          return cash.getCash(product);
 }
}
public class  RebateCash extends CashDecoratot
{
    public RebateCash(Cash cash)
    {
super(cash);
}
public double getCash(String product)
{
return super.getCash(product) * 0.1;
}
}
main :
Cash cash = new CashImpl();
CashDecorator  rebateCash = new  RebateCash(cash);
 rebateCash.getCash("test");

迭代器模式

在开发中经常需要将一个对象一个集合中,或者容器中,这个时候通常需要对集合或是同期进行访问,很明显的对集合或是容器的访问就是遍历,这就要用到迭代器模式。
java 中集合的遍历都用到了迭代器模式

访问者模式

访问者模式把数据结构和作用于结构上的操作之间进行解耦,因为增加一个新的操作就意味着增加一个新的访问者,所以增加新的操作很容易。
访问者模式b一般分为四个角色:

IElement 抽象的事物元素功能接口,定义了固定功能方法以及可变公恩那个的接口

Element 具体功能的实现

IVistor 访问接口 为所有访问者声明一个visit方法,用来代表对对象结构添加的功能

Vistor:具体访问者的实现类,实现真正被添加到对象结构中的功能。

职责链模式

职责链模式在程序开发中应用十分广泛,经常使用公文审批,出差报支当中,职责链模式的作用就是将对象各自处理职责的分开。
能够解决if语句过多的事情。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×