设计模式

设计模式

面向对象编程思想

简介

从面向对象编程思想是如何解决软件开发中各种疑难问题的角度,讲述面向对象编程思想的理解,梳理面向对象四大基本特性、七大设计原则和23种设计模式之间的关系

软件开发中疑难问题:

软件复杂庞大;

很多软件很难维护;

需求不断变更;

软件开发中存在很多很多的问题,上面三个问题只是从程序开发和设计的角度看到的部分问题。要解决上面软件开发的问题,就要求我们编写(设计)的软件具有很好的可读性、可维护性和可扩展性,并且还要保证代码具有高内聚低耦合。

四大基本特性

OOP(面向对象编程)的四大特性:抽象、封装、多态、继承。

抽象:

抽象是提取现实世界中某事物的关键特性,为该事物构建模型的过程。对同一事物中不同的需求下,需要提取的特性可能不一样。得到的抽象模型中一般包含:属性(数据)和操作(行为)。这个抽象模型我们称之为类,通过对类进行实例化得到具体的对象。

封装:

封装可以使类具有独立性和隔离性,从而保证类的高内聚。只暴露给类外部或者子类必须的属性和操作。类封装的实现依赖类的修饰符(public、protected和private)。

继承:

继承是对现有类的一种复用机制。一个类如果继承现有的类,则这个类将拥有被继承类的所有非私有特性(属性和操作)。这里指的继承包含类的继承和接口的实现。常见的继承方法有共有继承、私有继承、多重继承、多层继承。

多态:

多态是中继承的基础上实现的。多态的三个要素:继承、重写和父类引用指向子类的对象。父类引用指向不同的子类对象时,调用相同的方法,呈现出不同的行为;就是类的多态性。多态还可分为编译时多态(静态多态性)和运行时多态(动态多态性)。另外类的函数重载、运算符重载,也可算为多态的特性。

内聚:

顾名思义,表示内部间聚集、关联的程度,那么高内聚就是指要高度的聚集和关联。

高内聚是指类与类之间的关系而定,高,意思是他们之间的关系要简单,明了,不要有很强的关系,不然,运行起来就会出问题。一个类的运行影响到其他的类。

由于高内聚具备可靠性,可重用性,可读性等优点,模块设计推荐采用高内聚。内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。

内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。

耦合:

是对模块间关联程度的度量。

耦合的强弱取决与模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。

模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。

模块间联系越多,其耦合性越强,同时表明其独立性越差。降低模块间的耦合度能减少模块间的影响,防止对某一模块修改所引起的“牵一发动全身”的水波效应,保证系统设计顺利进行。 耦合度就是某模块(类)与其它模块(类)之间的关联

七大设计原则

在面向对象四大基础特性之上,我们在做面向对象设计时,还需要遵循一些基本设计原则。

下面是这七大原则的详细描述:

一、设计模式的七大原则

1、单一职责原则(SRP)

对类来说,即一个类应该只负责一项职责。如类A负责两个不同职责:职责1,职责2。当职责1需求变更而改变A时,可能造成职责2执行错误,所以要将类A的粒度分解为A1,A2。

2、开闭原则(OCP)

开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热拔插的效果,所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。

在面向对象的编程中,开闭原则是最基础的原则,起到总的指导作用,其他原则(单一职责、里氏替换、依赖倒置等)都是开闭原则的具体形态,即其他原则都是开闭原则的手段和工具。

举个简单例子,这里有个生产电脑的公司,根据输入的类型,生产出不同的电脑,代码如下:

interface Computer {}
class Macbook implements Computer {}
class Surface implements Computer {}
class Factory {
    public Computer produceComputer(String type) {
        Computer c = null;
        if(type.equals("macbook")){
            c = new Macbook();
        }else if(type.equals("surface")){
            c = new Surface();
        }
        return c;
    }   
}

显然上面的代码违背了开放 - 关闭原则,如果需要添加新的电脑产品,那么修改 produceComputer 原本已有的方法,正确的方式如下:

interface Computer {}
class Macbook implements Computer {}
class Surface implements Computer {}
interface Factory {
    public Computer produceComputer();
}
class AppleFactory implements Factory {
    public Computer produceComputer() {
        return new Macbook();
    }
}
class MSFactory implements Factory {
    public Computer produceComputer() {
        return new Surface();
    }
}
3、里氏代换原则(LSP) (面试常问)

在面向对象的语言中,继承是必不可少的,它主要有以下几个优点:

代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;

提高代码的可重用性;

提高代码的可扩展性;

提高产品或项目的开放性。

相应的,继承也存在缺点,主要体现在以下几个方面:

继承是入侵式的。只要继承,就必须拥有父类的所有属性和方法;

降低代码的灵活性。子类必须拥有父类的属性和方法,使子类受到限制;

增强了耦合性。当父类的常量、变量和方法修改时,必须考虑子类的修改,这种修改可能造成大片的代码需要重构。

里氏代换原则中说: 所有引用父类的地方必须能透明地使用其子类对象。清晰明确地说明只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道父类还是子类;但是反过来则不可以,有子类的地方,父类未必就能适应。

LSP是继承复用的基石,只有衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。

通俗理解:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。

示例:

我们需要完成一个两数相减的功能
class A{
    public int func1(int a, int b)
    {return a-b;}
}
public class Client{
    public static void main(String[] args){
        A a = new A();
        System.out.println("100-50="+a.func1(100, 50));
        System.out.println("100-80="+a.func1(100, 80));
    }
}
运行结果:
100-50=50
100-80=20
//后来,我们需要增加一个新的功能:
//完成两数相减,然后再与100求和,由类B来负责。
//即类B需要完成两个功能:
//两数相减
//然后再加100
class B extends A{  
/*
如果B继承A的时候把func1方法重写了,
比如重写成一个计算加法的结果的,
此时就违反了里氏代换原则,导致父类原有的方法功能被改变
*/
    public int func1(int a, int b){  
        return a+b;  
    }  
      
    public int func2(int a, int b){  
        return func1(a,b)+100;  
    }  
}  
public class Client{
    public static void main(String[] args){
        B b = new B();
        System.out.println("100-50="+b.func1(100, 50));
        System.out.println("100-80="+b.func1(100, 80));
        System.out.println("100+20+100="+b.func2(100, 20));}
}
4、依赖倒转原则(DIP)

开闭原则的基础,具体内容:针对接口编程,不要对实现编程;

高层模块不应该依赖低层模块。两个都应该依赖抽象。

抽象不应该依赖细节。细节应该依赖抽象。

//例子:以顾客购物场景为例,假设今天,顾客想去万达买点东西,
//就有了下面代码
public class WanDaShop  {
    public String sell(){
        return "万达购物";
    }
}	
class Customer {
    public void shopping(WanDaShop shop) {
        //购物
        System.out.println(shop.sell());
    }
}
//第二天,顾客觉得万达东西太贵了,想换一家店购买,
//比如永辉超市,于是又修改代码为:
public class YongHuiMarket  {
    public String sell(){
        return "永辉购物";
    }
}
class Customer {
    public void shopping(YonghuiShop shop) {
        //购物
        System.out.println(shop.sell());
    }
}
//此时,缺点已经体现出来了,顾客每更换一家商店,
//都要修改一次代码,这明显违背了开闭原则。
//存在以上缺点的原因是:顾客类设计时同具体的商店类绑定了,
//这违背了依赖倒置原则。
//解决方法是:定义“永辉超市”和“万达的”的共同接口 Shop,
//顾客类面向该接口编程,其代码修改如下:
public interface Shop {
    public String sell();
}
class Customer {
    public void shopping(Shop shop) {
        //购物
        System.out.println(shop.sell());
    }
}
//实现类
public class WanDaShop implements Shop{
    public String sell();
}

//测试类
public class Test {
    public static void main(String[] args) {
        Customer customer = new Customer();
        customer.shopping(new YongHuiMarket());
    }
}
//这样,不管顾客类 Customer 访问什么商店,或者增加新的商店,
//都不需要修改原有代码了。
5、接口隔离原则(ISP)

使用多个隔离的接口,比是用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便.(降低依赖,降低耦合)。

根据接口隔离原则,当一个接口太大的时候,我们就需要将它分割为一些更加细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干。

例子:以学生成绩管理系统为例,学生成绩管理一般包含插入成绩、删除成绩、修改成绩、计算总分、计算均分、打印成绩信息、査询成绩信息等功能,如果将这些功能全部放到一个接口中显然不太合理,正确的做法是将它们分别放在输入模块、统计模块和打印模块等 3 个模块中,其类图如图所示。

6、迪米特法则(LoD)

迪米特法则也称最少知道原则:如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。

根本思想:强调了类之间的松耦合。

示例:以明星和经纪人关系为例,明星由于全身心投入艺术,所以许多日常事务由经纪人负责处理,如与粉丝的见面会,与媒体公司的业务洽淡等。这里的经纪人是明星的朋友,而粉丝和媒体公司是陌生人,所以适合使用迪米特法则,其类图如图所示:

/*
示例:以明星和经纪人关系为例,明星由于全身心投入艺术,
所以许多日常事务由经纪人负责处理,如与粉丝的见面会,
与媒体公司的业务洽淡等。这里的经纪人是明星的朋友,
而粉丝和媒体公司是陌生人,所以适合使用迪米特法则,其类图如图所示
*/
public class LoDtest {
    public static void main(String[] args) {
        Agent agent = new Agent();
        agent.setStar(new Star("周杰伦"));
        agent.setFans(new Fans("粉丝某某"));
        agent.setCompany(new Company("中国传媒有限公司"));
        agent.meeting();
        agent.business();
    }
}
//经纪人
class Agent {
    private Star myStar;
    private Fans myFans;
    private Company myCompany;
    public void setStar(Star myStar) {
        this.myStar = myStar;
    }
    public void setFans(Fans myFans) {
        this.myFans = myFans;
    }
    public void setCompany(Company myCompany) {
        this.myCompany = myCompany;
    }
    public void meeting() {
        System.out.println(myFans.getName() + "与明星" + 
                           myStar.getName() + "见面了。");
    }
    public void business() {
        System.out.println(myCompany.getName() + "与明星" + 
                           myStar.getName() + "洽淡业务。");
    }
}
//明星
class Star {
    private String name;
    Star(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}
//粉丝
class Fans {
    private String name;
    Fans(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}
//媒体公司
class Company {
    private String name;
    Company(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}
7、合成复用原则(CRP)

合成复用原则就是在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用功能的目的。简言之:复用时要尽量使用组合/聚合关系(关联关系),少用继承。

它要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

如果要使用继承关系,则必须严格遵循里氏替换原则。合成复用原则同里氏替换原则相辅相成的,两者都是开闭原则的具体实现规范。

示例:

以汽车分类管理系统为例,汽车按“动力源”划分可分为汽油汽车、电动汽车等;按“颜色”划分可分为白色汽车、黑色汽车和红色汽车等。如果同时考虑这两种分类,其组合就很多。

我们先看用继承关系实现的汽车分类的类图:

从上图可以看出用继承关系实现会产生很多子类,而且增加新的“动力源”或者增加新的“颜色”都要修改源代码,这违背了开闭原则,显然不可取。

但如果改用组合关系实现就能很好地解决以上问题:

设计模式的分类:

创建型:

1、单例模式(Singleton):

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

2、简单工厂模式(Factory Pattern):

定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类。

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。

这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

介绍

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

主要解决:主要解决接口选择的问题。

何时使用:我们明确地计划不同条件下创建不同实例时。

如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。

关键代码:创建过程在其子类执行。

应用实例: 1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 2、Hibernate 换数据库只需换方言和驱动就可以。

优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。

注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

示例:

我们将创建一个 Shape 接口和实现 Shape 接口的实体类。

下一步是定义工厂类 ShapeFactory。

FactoryPatternDemo,我们的演示类使用 ShapeFactory 来获取 Shape 对象。

它将向 ShapeFactory 传递信息(CIRCLE / RECTANGLE / SQUARE),以便获取它所需对象的类型。

//步骤 1
//创建一个接口:
//Shape.java
public interface Shape {    void draw(); }
//步骤 2
//创建实现接口的实体类。
public class Rectangle implements Shape {
   @Override
   public void draw() {
      System.out.println("画长方形");
   }
}
public class Square implements Shape {
   @Override
   public void draw() {
      System.out.println("画正方形");
   }
}
public class Circle implements Shape {
   @Override
   public void draw() {
      System.out.println("画圆形");
   }
}
//步骤3
//创建一个工厂,生成基于给定信息的实体类的对象。
public class ShapeFactory {
   //使用 getShape 方法获取形状类型的对象
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equalsIgnoreCase("圆形")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("长方形")){
         return new Rectangle();
      } else if(shapeType.equalsIgnoreCase("正方形")){
         return new Square();
      }
      return null;
   }
}
//步骤 4
//使用该工厂,通过传递类型信息来获取实体类的对象。
FactoryPatternDemo.java
public class FactoryPatternDemo {
   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();
      //获取 Circle 的对象,并调用它的 draw 方法
      Shape shape1 = shapeFactory.getShape("圆形");
      //调用 Circle 的 draw 方法
      shape1.draw();
      //获取 Rectangle 的对象,并调用它的 draw 方法
      Shape shape2 = shapeFactory.getShape("长方形");
      //调用 Rectangle 的 draw 方法
      shape2.draw();
      //获取 Square 的对象,并调用它的 draw 方法
      Shape shape3 = shapeFactory.getShape("正方形");
      //调用 Square 的 draw 方法
      shape3.draw();
   }
}
工厂方法模式
public interface Phone {
    void getPhone();
}

public class XiaoMi implements Phone{
    @Override
    public void getPhone() {
        System.out.println("获取小米手机");
    }
}

public class Apple implements Phone{
    @Override
    public void getPhone() {
        System.out.println("拿到了苹果手机");
    }
}

public class HuaWei implements Phone{
    @Override
    public void getPhone() {
        System.out.println("获取华为手机!");
    }
}


public interface PhoneFactory {
        Phone getBrandPhone();
}



public class AppleFactory implements PhoneFactory{
    @Override
    public  Phone getBrandPhone() {

        return new Apple();
    }
}

public class HuaWeiFactory implements PhoneFactory{
    @Override
    public Phone getBrandPhone() {
        return new HuaWei();
    }
}


public class XiaoMiFactory implements PhoneFactory{
    @Override
    public Phone getBrandPhone() {
        return new XiaoMi();
    }
}

public class Consumer {
    public static void main(String[] args) {

        Phone xiaomi = new XiaoMiFactory().getBrandPhone();
        xiaomi.getPhone();
        Phone huawei = new HuaWeiFactory().getBrandPhone();
        huawei.getPhone();
        Phone apple = new AppleFactory().getBrandPhone();
        apple.getPhone();

    }
}
3、抽象工厂(Abstract Factory):

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

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

介绍

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

主要解决:主要解决接口选择的问题。

何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。

如何解决:在一个产品族里面,定义多个产品。

关键代码:在一个工厂里聚合多个同类产品。

应用实例:工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况(现实中是不存在的,要不然,没法进入共产主义了,但有利于说明抽象工厂模式),在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 OOP 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。

优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。

使用场景: 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。

注意事项:产品族难扩展,产品等级易扩展。

示例

我们将创建 Shape 和 Color 接口和实现这些接口的实体类。

下一步是创建抽象工厂类 AbstractFactory。接着定义工厂类 ShapeFactory 和 ColorFactory,这两个工厂类都是扩展了 AbstractFactory。然后创建一个工厂创造器/生成器类 FactoryProducer。

AbstractFactoryPatternDemo,我们的演示类使用 FactoryProducer 来获取 AbstractFactory 对象。

它将向 AbstractFactory 传递形状信息 Shape(CIRCLE / RECTANGLE / SQUARE),以便获取它所需对象的类型。同时它还向 AbstractFactory 传递颜色信息 Color(RED / GREEN / BLUE),以便获取它所需对象的类型。

//步骤 1
//为形状创建一个接口。
public interface Shape {
   void draw();
}
//步骤2
//创建实现接口的实体类。
public class Rectangle implements Shape {
   @Override
   public void draw() {
      System.out.println("画长方形");
   }
}
public class Square implements Shape {
   @Override
   public void draw() {
      System.out.println("画正方形");
   }
}
public class Circle implements Shape {
   @Override
   public void draw() {
      System.out.println("画圆形");
   }
}
//步骤3
//为颜色创建一个接口。
public interface Color {   
    void fill();
}
//步骤4
//创建实现接口的实体类。
public class Red implements Color {
   @Override
   public void fill() {
      System.out.println("红色");
   }
}
public class Green implements Color {
   @Override
   public void fill() {
      System.out.println("绿色");
   }
}
public class Blue implements Color {
   @Override
   public void fill() {
      System.out.println("蓝色");
   }
}
//步骤5
///为 Color 和 Shape 对象创建抽象类来获取工厂。
public abstract class AbstractFactory {
   public abstract Color getColor(String color);
   public abstract Shape getShape(String shape) ;
}
//步骤6
//创建扩展了 AbstractFactory 的工厂类,
//基于给定的信息生成实体类的对象。
public class ShapeFactory extends AbstractFactory {
   @Override
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equalsIgnoreCase("圆形")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("长方形")){
         return new Rectangle();
      } else if(shapeType.equalsIgnoreCase("正方形")){
         return new Square();
      }
      return null;
   }
   @Override
   public Color getColor(String color) {
      return null;
   }
}
public class ColorFactory extends AbstractFactory {
   @Override
   public Shape getShape(String shapeType){
      return null;
   }
   @Override
   public Color getColor(String color) {
      if(color == null){
         return null;
      }        
      if(color.equalsIgnoreCase("红色")){
         return new Red();
      } else if(color.equalsIgnoreCase("绿色")){
         return new Green();
      } else if(color.equalsIgnoreCase("蓝色")){
         return new Blue();
      }
      return null;
   }
}
//步骤 7 
//创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。
public class FactoryProducer {
   public static AbstractFactory getFactory(String choice){
      if(choice.equalsIgnoreCase("图形")){
         return new ShapeFactory();
      } else if(choice.equalsIgnoreCase("颜色")){
         return new ColorFactory();
      }
      return null;
   }
}
//步骤 8 
//使用 FactoryProducer 来获取 AbstractFactory,
//通过传递类型信息来获取实体类的对象。 
public class AbstractFactoryPatternDemo {
   public static void main(String[] args) {
      //获取形状工厂
      AbstractFactory shapeFactory = FactoryProducer.getFactory("图形");
      //获取形状为 Circle 的对象
      Shape shape1 = shapeFactory.getShape("圆形");
      //调用 Circle 的 draw 方法
      shape1.draw();
      //获取形状为 Rectangle 的对象
      Shape shape2 = shapeFactory.getShape("长方形");
      //调用 Rectangle 的 draw 方法
      shape2.draw();
      //获取形状为 Square 的对象
      Shape shape3 = shapeFactory.getShape("正方形");
      //调用 Square 的 draw 方法
      shape3.draw();
      //获取颜色工厂
      AbstractFactory colorFactory = FactoryProducer.getFactory("颜色");
      //获取颜色为 Red 的对象
      Color color1 = colorFactory.getColor("红色");
      //调用 Red 的 fill 方法
      color1.fill();
      //获取颜色为 Green 的对象
      Color color2 = colorFactory.getColor("绿色");
      //调用 Green 的 fill 方法
      color2.fill();
      //获取颜色为 Blue 的对象
      Color color3 = colorFactory.getColor("蓝色");
      //调用 Blue 的 fill 方法
      color3.fill();
   }
}
//步骤 9 执行程序,输出结果
4、建造模式(Builder):

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

5、原型模式(Peototype):

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

行为型:

6、迭代器模式(Iterator):

提供一个方法顺序访问一个聚合对象的各个元素,而又不需要暴露该对象的内部表示。

7、观察者模式(Observer):

定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。

8、模板方法(Temolate Method):

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤。

9、命令模式(Command):

讲一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志,以及支持可撤销的操作。

10、状态模式(State):

允许对象在其内部状态改变时改变他的行为。

11、策略模式(Strategy):

定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。

12、职责链模式(ChinaOfResponibility):

使多个对象都有机会请求处理请求,从而避免请求的发送者和接收者之间的耦合关系。

13、中介者模式(Mediator):

用一个中介对象封装一些列的对象交互。

14、访问者模式(Visitor):

表示一个作用于某对象结构中的各元素的操作,它可以在不改变各元素类的前提下定义作用域这个元素的新操作。

15、解释器模式(Interpreter):

给定一个语言,定义它的文法的一个表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

16、备忘录模式(Memento):

在不破坏对象的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

结构型:

17、组合模式(Composite):

将对象组合树形结构以表示部分整体的关系。

18、外观模式(Facade):

为子系统中的一组接口提供一致的界面,façade提供了一高层接口。这个接口使得子系统更容易使用。

19、代理模式(Proxy):

为其他对象提供一种代理以控制对这个对象的访问。

20、适配器模式(Adapter):

将一类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作那些类可以在一起作用。

21、装饰模式(Decrator):

动态地给一个对象增加一些额外的职责,就增加的功能来说,Decorator模式相比生产子类更加灵活。

22、桥接模式(Biedge):

将抽象部分与它的实现部分相分离,使他们可以独立的变化。

23、享元模式(Flyweight):

运用共享技术有效地支持大量细粒度的对象。

  • 24
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值