设计模式之组合模式

定义:组合模式就是把一些现有的对象或者元素,经过组合后组成新的对象,新的对象提供内部方法,可以让我们很方便的完成这些元素或者内部对象的访问和操作。组合模式是将一系列对象组合成树形结构用来表示整体和部分之间的关系,组合模式的主要目的是达到,访问组合对象和访问单个对象具有一致性。这里的组合对象比较特殊,本身他可以是由其他的对象组合而成,同时,这个组合对象又可以是组成更复杂对象的一个部分。如下结构图:日期等单个对象组合成查询组件,查询组件和其他组件或对象组合成分页组件。组合模式以不遵守单一责任原则换取透明性,让Client将组合和叶节点一视同仁。

角色:
1.Component:组合对象或叶子节点的接口
2.Leaf:叶子节点,最末节。
3.Composite:组合节点。
4.Client客户端

优点:组合模式可以降低系统的复杂度,因为我们可以把复杂的组件看作另一个组件的组成部分来处理。组合模式可以很容易的增加新的构件。使用组合模式可以使客户端变的很容易设计,因为客户端可以对组合和叶节点一视同仁。

缺点:使用组合模式后,控制树枝构件的类型不太容易。用继承的方法来增加新的行为很困难。

应用:以下实例中,客户端可单独获取叶子对象,也可以通过组合获取叶子对象。
1.声明Component接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public abstract class Component 
{
public void add(Component component)
{

}

public void remove(Component component)
{

}

public Component getChild(int i)
{

}

public void operation()
{

}
}

2.声明叶子节点,叶子节点没有添加和删除节点功能,只实现自身的operation

1
2
3
4
5
6
7
public class Leaf extends Component
{
public Override void operation()
{
/ /your code
}
}

3.声明组合节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
```
public class Composite extends Component
{
ArrayList<Component> components = new ArrayList<Component>();

public Override void add(Component component)
{
  components.add(component);
}

public Override void remove(Component component)
{
  components.remove(component);
}

public Override Component getChild(int i)
{
  return components.get(i);
}

public Override void operation()
{
for (Component component : components)
{
component.operation();
}
  }
}

设计模式之外观模式

定义:将细粒度的对象包装成粗粒度的对象,应用程序通过访问这个外观对象,来完成细粒度对象的调用,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性。

优点:1、减少系统相互依赖。 2、提高灵活性。 3、提高了安全性。

缺点:不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。

结构图:通过外观对象来组织细粒度的服务的调用,外观对象提供给外部应用程序可以使用的服务,而具体的调用细粒度的过程则被外观对象给封装起来,当然这个过程就是封装变化的部分,而将变化的部分与应用程序进行隔离,无疑对程序的易用性和可维护性都是很大的提高。

应用:一下案例通过客户端通过外观对象调用不同的形状对象的服务,减少了客户端和应用端的交互,简化的步骤,将外观对象做成单例类,可以在使用对象时减少内存的分配。
1.创建一个接口。

public interface Shape { void draw();}
2.创建接口的实现类(对象):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Rectangle : Shape
{
public void Draw() { }
}

public class Square : Shape
{
public void Draw(){ }
}

public class Circle : Shape
{
public void Draw() { }
}

3.创建外观对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ShapeMaker {
private Shape circle;
private Shape rectangle;
private Shape square;

public ShapeMaker() {
circle = new Circle();
rectangle = new Rectangle();
square = new Square();
}

public void drawCircle(){
circle.draw();
}
public void drawRectangle(){
rectangle.draw();
}
public void drawSquare(){
square.draw();
}
}

4.创建客户端,调用外观对象:

1
2
3
4
5
6
7
8
9
public class Client {
public static void main(String[] args) {
ShapeMaker shapeMaker = new ShapeMaker();

shapeMaker.drawCircle();
shapeMaker.drawRectangle();
shapeMaker.drawSquare();
}
}

Unity 单例模版

c#:使用泛型实现单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System; 
using System.Collections.Generic;
using System.Text; using System.Reflection;
/// <summary> /// 1.泛型 /// 2.反射 /// 3.抽象类 /// 4.命名空间 /// </summary>
namespace QFramework
{
  public abstract class QSingleton<T> where T : QSingleton<T>
  {
    protected static T instance = null; protected QSingleton() { }
  public static T Instance()
  {
      if (instance == null)
      {
// 先获取所有非public的构造方法
ConstructorInfo[] ctors = typeof(T).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);
// 从ctors中获取无参的构造方法
ConstructorInfo ctor = Array.Find(ctors, c => c.GetParameters().Length == 0);
if (ctor == null)
throw new Exception("Non-public ctor() not found!");
// 调用构造方法
instance = ctor.Invoke(null) as T;
      }
    return instance;
    }
  }
}

unity实现MonoBehaviour 单例,约束GameObject的个数,这个需求,还没有思路,只好在游戏运行时判断有多少个GameObject已经挂上了该脚本,然后如果个数大于1抛出错误即可。在脚本销毁时,把静态实例置空。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using UnityEngine;
/// <summary> /// 需要使用Unity生命周期的单例模式 /// </summary>
namespace QFramework
{
  public abstract class QMonoSingleton<T> : MonoBehaviour where T : QMonoSingleton<T>
  {
  protected static T instance = null;
    public static T Instance()
    {
  if (instance == null)
  {
 instance = FindObjectOfType<T>();
        if (FindObjectsOfType<T>().Length > 1)
{
QPrint.FrameworkError ("More than 1!");
return instance;
        }
if (instance == null)
        {
string instanceName = typeof(T).Name; QPrint.FrameworkLog ("Instance Name: " + instanceName);
GameObject instanceGO = GameObject.Find(instanceName);
if (instanceGO == null) instanceGO = new GameObject(instanceName);
instance = instanceGO.AddComponent<T>();
DontDestroyOnLoad(instanceGO);
//保证实例不会被释放
QPrint.FrameworkLog ("Add New Singleton " + instance.name + " in Game!");
}
else {
QPrint.FrameworkLog ("Already exist: " + instance.name);
}
}
return instance;
}
  protected virtual void OnDestroy()
  {
instance = null;
  }
}

MVC 模式

定义:MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。

角色:
1.Model(模型) :模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。
2.View(视图) :视图代表模型包含的数据的可视化,负责输出数据或UI。
3.Controller(控制器) : 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。

优点:
1.有多个视图对应一个模型的能力。
2.由于一个应用被分离为三层,因此有时改变其中的一层就能满足应用的改变。一个应用的业务流程或者业务规则的改变只需改动MVC的模型层。
3.由于不同的层各司其职,每一层不同的应用具有某些相同的特征,有利于通过工程化、工具化产生管理程序代码。

缺点:
(1)增加了系统结构和实现的复杂性。对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。
(2)视图与控制器间的过于紧密的连接。视图与控制器是相互分离,但却是联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。
(3)视图对模型数据的低效率访问。依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。
(4) 目前,一般高级的界面工具或构造器不支持MVC架构。改造这些工具以适应MVC需要和建立分离的部件的代价是很高的,从而造成使用MVC的困难。

使用:
1.创建模型类(数据层):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Student 
{

private String rollNo;

private String name;

public String getRollNo() {

return rollNo;

}

public void setRollNo(String rollNo) {

this.rollNo = rollNo;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}
}

2.创建视图类:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class StudentView 
{

public void printStudentDetails(String studentName, String studentRollNo){

System.out.println("Student: ");

System.out.println("Name: " + studentName);

System.out.println("Roll No: " + studentRollNo);

}
}

3.创建控制器类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class StudentController {

private Student model;
private StudentView view;

public StudentController(Student model, StudentView view)
  {
this.model = model;
this.view = view;
}

public void setStudentName(String name)
  {
model.setName(name);
}

public String getStudentName()
  {
return model.getName();
}

public void setStudentRollNo(String rollNo){

model.setRollNo(rollNo);

}

public String getStudentRollNo()
  {
return model.getRollNo();
}

public void updateView()
  {
view.printStudentDetails(model.getName(), model.getRollNo());
}
}

4.使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class MVCPatternDemo {

public static void main(String[] args)
  {
//从数据可获取学生记录
Student model = retriveStudentFromDatabase();

//创建一个视图:把学生详细信息输出到控制台
StudentView view = new StudentView();

StudentController controller = new StudentController(model, view);
controller.updateView();

//更新模型数据
controller.setStudentName("John");
controller.updateView();
}

private static Student retriveStudentFromDatabase()
  {
Student student = new Student();
student.setName("Robert");
student.setRollNo("10");
return student;
}
}

设计模式之原型模式

定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的实例。换句话说,原型模式就是通过复制现在已经存在的对象来创建一个新的对象,而不是使用 new 来创建一个对象。这个复制的结果有2种,一种是是浅复制,另一种是深复制。

浅复制:通过一个原型实例(这里暂称为老对象)克隆所得到的对象(这里暂时称为新对象),新对象中所有的值类型变量都含有与老对象相同的值,新对象所有的对其他对象的引用都和老对象指向同一个地方,即对引用类型来说,老对象和新对象指向同一个引用对象。

深复制:和浅复制就一点不同,那就是,新对象所有的对其他对象的引用都是指向了复制过的对象,而不再是和老对象指向同一个对象,也就是说,克隆新对象的同时,克隆了老对象的所有引用并将新对象指向这些引用。

优点:复制一个对象一般情况下会比创建一个对象性能更高。

缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。 3、逃避构造函数的约束。

结构图:

应用:
1.定义一个接口, 用来表述所有的颜色对象接口:

1
2
3
4
5
6
7
8
public interface IColorDemo 
{
IColorDemo Clone();
int Red { get; set; }
int Green { get; set; }
Quote quoteInstance{get;set}
}
publc class Quote{}

2.具体类的实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 public class RedColor : IColorDemo 
{
private int red;
private int green;
Quote quoteInstance{get;set}
public int Red
{
get { return this.red; }
set { this.red = value; }
}
public int Green
{
get { return this.green; }
set { this.green = value; }
}
}

//浅复制

public Override IColorDemo Clone()
{
return (IColorDemo)this.MemberwiseClone();
}
//深复制,获取浅表副本的同时复制引用。

1
2
3
4
5
6
7
 public Override IColorDemo Clone() 
{
IColorDemo color = this.MemberwiseClone();
Quote q = new Quote();
color.quoteIntance = q;
return color;
}

设计模式之建造者模式

定义:建造者模式使用多个简单的对象一步一步构建成一个复杂的对象,修改时只需要修改其中相应的一小部分,避免牵一发而动全身。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

角色:

1.AbstractBuilder:抽象建造者
为创建一个Product对象的各个部件指定抽象接口,将建造的具体过程交与它的子类来实现。一般会有两部分抽象方法,一部分用来建造产品,一个是用来返回产品。如下图,buildPart1和buildPart2用来构造产品,retrieveResult返回产品。
2.ConcreteBuilder:具体建造者
实现抽象建造者的抽象方法,之所以这样,是为了便于不同情况下的扩充。
3.Director:导演者
负责调用适当的建造者来组建产品,导演类一般不与产品类发生依赖关系,与导演类直接交互的是建造者类。一般来说,导演类被用来封装程序中易变的部分。
4.Product:产品类
表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。产品类是一个具体的类,而非抽象类。实际编程中,产品类可以是由一个抽象类与它的不同实现组成,也可以是由多个抽象类与他们的实现组成。
结构图:(注:原文这里应有一张建造者模式结构图,但当前仓库未保留对应图片。)

优点: 1、建造者独立,易扩展。 2、便于控制细节风险。

缺点:1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

应用:以下案例示范将一餐饭(product)拆解为每份食物、包装,更改单个食物的属性不需要修改这餐饭。
1.创建一个表示食物条目和食物包装的接口。

1
2
3
4
5
6
7
8
9
10
public interface Item
{
public String name();
public Packing packing();
public float price();
}
public interface Packing
{
  public String pack();
}

2.创建实现 Packing 接口的实体类。

1
2
3
4
5
6
7
8
9
public class Wrapper implements Packing 
{
public String pack() { return "Wrapper";}
}

public class Bottle implements Packing
{
public String pack() { return "Bottle";}
}

3.创建实现 Item 接口的抽象类,该类提供了默认的功能。

1
2
3
4
5
6
7
8
9
10
11
public abstract class Burger : Item 
{
public Packing packing() { return new Wrapper(); }
public abstract float price();
}

public abstract class ColdDrink : Item
{
public Packing packing() { return new Bottle();}
public abstract float price();
}

4.创建扩展了 Burger 和 ColdDrink 的实体类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class VegBurger extends Burger 
{
public float price() { return 25.0f; }
public String name() { return "Veg Burger"; }
}

public class ChickenBurger extends Burger
{
public float price() { return 50.5f; }
public String name() { return "Chicken Burger";}
}
public class Coke extends ColdDrink
{
public float price() { return 30.0f;}
public String name() { return "Coke";}
}

public class Pepsi extends ColdDrink
{
public float price() {return 35.0f; }
public String name() { return "Pepsi";}
}

5.建一个 Meal 类,带有上面定义的 Item 对象,类似定义一餐所包含的类目。

1
2
3
4
5
6
7
8
9
10
11
12
public class Meal 
{
private List<Item> items = new ArrayList<Item>();
public void addItem(Item item){ items.add(item); }

public float getCost()
{
float cost = 0.0f;
for (Item item : items) { cost += item.price(); }
return cost;
}
}

5.使用:

Meal meal = new Meal();
meal.addItem(new VegBurger());
meal.addItem(new Coke());
meal.getcost()获取消费

设计模式之单例模式

定义:对于一个软件系统的某些类而言,我们无须创建多个实例。为了节约系统资源,有时需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例。为了确保对象的唯一性,我们可以通过单例模式来实现,这就是单例模式的需求所在。

优点:
-单例模式提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它。

  • 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
    -允许可变数目的实例。基于单例模式我们可以进行扩展,使用与单例控制相似的方法来获得指定个数的对象实例,既节省系统资源,又解决了单例单例对象共享过多有损性能的问题。

缺点:

  • 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
  • 单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身的功能融合到一起。
    -现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收的技术,因此,如果实例化的共享对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致共享的单例对象状态的丢失。

应用:
1.懒汉式

1
2
3
4
5
6
7
8
9
10
11
12
13
class Singleton
{
private staticSingleton _insance = null;
private Singleton() {……} //
public static Singleton getInstance()
{
if (_insance == null)
{
_insance = new Singleton();
}
return _insance;
}
}

2.饿汉士:由于懒汉式_insance = new XXX();需要一定时间,当new未完成时调用会出现两个实例化,这就不满足单例模式了,以下写法在系统加载时由于需要创建单例对象,加载时间可能会比较长。

1
2
3
4
5
6
7
8
9
class Singleton
{
private static Singleton _insance = new Singleton();
private Singleton() {……} //
public static Singleton getInstance()
{
return _insance;
}
}

3.考虑多线程情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Singleton {  

private volatile static Singleton singleton;

private Singleton (){}

public static Singleton getSingleton() {

if (singleton == null) {

synchronized (Singleton.class) {

if (singleton == null) {

singleton = new Singleton();

}

}

}

return singleton;

}
}
}

设计模式之抽象工厂模式

定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。在工厂模式的基础上,在工厂层面在封装一层(简单工厂只在产品上包装一层)。抽象工厂模式适用于对“一系列相互依赖的对象”的创建工作,这些对象是相互依赖的,是有联系的。如果仅为一个对象的创建则用简单工厂模式或工厂方法模式完全可以实现,没有必要用抽象工厂模式。

角色:
抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。
具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象,生成一系列具体的产品
抽象产品角色:它是具体产品继承的父类或者是实现的接口。
具体产品角色:具体工厂角色所创建的对象就是此角色的实例。

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

缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。这是因为抽象工厂几乎确定了可以被创建的产品集合,支持新种类的产品就需要扩展该工厂接口,这将涉及抽象工厂类及其所有子类的改变。

使用:以下例子,通过抽象工厂AbstractFactory实例化具体工厂,通过抽象产品Shape实例化具体产品,之间通过两个参数颜色、颜色值或者形状、形状值确定最终的产品。
1.为形状创建接口,创建实现接口的实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface Shape 
{
void draw();
}
public class Rectangle: Shape
{
public void draw()
{
System.out.println("Inside Rectangle::draw() method.");
}
}
public class Square: Shape
{
public void draw()
{
System.out.println("Inside Square::draw() method.");
}
}

2.为颜色创建接口,创建实现接口的实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface Color 
{
  void draw();
}
public class Red: Color
{
public void draw()
    {
      System.out.println("Inside Red::draw() method.");
    }
}
public class Green: Color
{
public void draw()
    {
      System.out.println("Inside Green::draw() method.");
    }
}

3.为 Color 和 Shape 对象创建抽象类来获取工厂。AbstractFactory

public abstract class AbstractFactory
{
abstract Color getColor(String color);
abstract Shape getShape(String shape) ;
}
4.创建扩展了 AbstractFactory 的工厂类,基于给定的信息生成实体类的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class ShapeFactory : AbstractFactory
{
public Override Shape getShape(String shapeType)
{
if(shapeType == null){ return null; }

if(shapeType.equalsIgnoreCase("CIRCLE"))
{
return new Circle();
}
else if(shapeType.equalsIgnoreCase("RECTANGLE"))
{
return new Rectangle();
}
return null;
}

Override Color getColor(String color) { return null; }
}

public class ColorFactory extends AbstractFactory
{
public Override Shape getShape(String shapeType)
{ return null; }

Override Color getColor(String color)
{
if(color == null){
return null;
}
if(color.equalsIgnoreCase("RED"))
{
return new Red();
}
else if(color.equalsIgnoreCase("GREEN"))
{
return new Green();
}
}
return null;
}
}

5.创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FactoryProducer 
{
public static AbstractFactory getFactory(String choice)
{
if(choice.equalsIgnoreCase("SHAPE"))
{
return new ShapeFactory();
}
else if(choice.equalsIgnoreCase("COLOR"))
{
return new ColorFactory();
}
return null;
}
}

6.实例化:

AbstractFactory shapeFactory = FactoryProducer.getFactory(“SHAPE”);
AbstractFactory colorFactory = FactoryProducer.getFactory(“COLOR”);

设计模式之-工厂模式

定义:专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类(抽象类)或接口。简单工厂模式又称为静态工厂方法模式,属于类的创建型模式,通常根据一个条件(参数)来返回不同的类的实例。
它由三种角色组成(关系见下面的类图):
1、工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,负责通过不同条件创建不同产品。
2、抽象产品角色:它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。
3、具体产品角色:工厂类所创建的对象就是此角色的实例,是简单工厂模式的创建目标。

结构图:

优点:
· 简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。通过它,外界可以从直接创建具体产品对 象的尴尬局面中摆脱出来。
· 外界与具体类隔离开来,偶合性低。
· 明确区分了各自的职责和权力,有利于整个软件体系结构的优化。
-在简单工厂模式中最核心的部分—-工厂类不要根据传来的条件去动态创建产品类,利用反射机制去创建。把要实例化的类名放在应用程序配置文件中, 可以让文件更好维护。

缺点:
· 工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则
· 虽然简单工厂模式能够适应一定的变化,但是它所能解决的问题是远远有限的。它所能创建的类只能是事先就考虑到的,如果需要添加新的类,则就需要改变工厂类了。
-在添加新产品时,需要编写新的具体产品类(其实这不算一个缺点,因为这是不可避免的),要增加与之对应的具体工厂类。

应用:工厂类通过传入的参数确定实例化那种形状,形状的(具体产品)类继承自shape(抽象产品类)。

1.创建接口或抽象类:public interface Shape { void draw();}
2.创建实现接口的实体类,这些类最终会被工厂实例化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Rectangle: Shape 
{
public void draw()
  {
    System.out.println("Inside Rectangle::draw() method.");
  }
}
public class Square: Shape
{
public void draw()
  {
    System.out.println("Inside Square::draw() method.");
  }
}

3.创建工厂类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ShapeFactory 
{
//使用 getShape 方法获取形状类型的对象
public Shape getShape(String shapeType)
  {
if(shapeType == null)
    {
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE"))
    {
return new Circle();
}
    else if(shapeType.equalsIgnoreCase("RECTANGLE"))
   {
return new Rectangle();
}
return null;
}
}

4.通过传递类型信息创建并获取实例:
Shape shape1 = shapeFactory.getShape(“CIRCLE”);

设计模式中类的关系

  1. 依赖(Dependence)

依赖关系的定义为:对于两个相对独立的对象,当一个对象负责构造另一个对象的实例,或者依赖另一个对象的服务时,这两个对象之间主要体现为依赖关系。定义比较晦涩难懂,但在java中的表现还是比较直观的:类A当中使用了类B,其中类B是作为类A的方法参数、方法中的局部变量、或者静态方法调用。类上面的图例中:People类依赖于Book类和Food类,Book类和Food类是作为类中方法的参数形式出现在People类中的。

1
2
3
4
5
6
public class People{  
//Book作为read方法的形参
public void read(Book book){
System.out.println(“读的书是”+book.getName());
}
}

2.关联(Association)
单向关联:

双向关联:

对于两个相对独立的对象,当一个对象的实例与另一个对象的一些特定实例存在固定的对应关系时,这两个对象之间为关联关系。关联关系分为单向关联和双向关联。在java中,单向关联表现为:类A当中使用了类B,其中类B是作为类A的成员变量。双向关联表现为:类A当中使用了类B作为成员变量;同时类B中也使用了类A作为成员变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Son{  
//关联关系中作为成员变量的类一般会在类中赋值
Father father = new Father();
public void getGift(){
System.out.println(“从”+father.getName()+”获得礼物”);
}
}

public class Father{
Son son = new Son();
public void giveGift(){
System.out.println(“送给”+son.getName()+“礼物”);
}
}

3.聚合(Aggregation)

聚合关系是关联关系的一种,耦合度强于关联,他们的代码表现是相同的,仅仅是在语义上有所区别:关联关系的对象间是相互独立的,而聚合关系的对象之间存在着包容关系,他们之间是“整体-个体”的相互关系。没有车司机就不能发生开车这个行为。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class People{  
Car car;
House house;
//聚合关系中作为成员变量的类一般使用set方法赋值
public void setCar(Car car){
This.car = car;
}
public void setHouse(House house){
This.house = house;
}

public void driver(){
System.out.println(“车的型号:”+car.getType());
}
public void sleep(){
System.out.println(“我在房子里睡觉:”+house.getAddress());
}
}

4.组合(Composition)

相比于聚合,组合是一种耦合度更强的关联关系。存在组合关系的类表示“整体-部分”的关联关系,“整体”负责“部分”的生命周期,他们之间是共生共死的;并且“部分”单独存在时没有任何意义。在下图的例子中,People与Soul、Body之间是组合关系,当人的生命周期开始时,必须同时有灵魂和肉体;当人的生命周期结束时,灵魂肉体随之消亡;无论是灵魂还是肉体,都不能单独存在,他们必须作为人的组成部分存在。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Public class People{  
Soul soul;
Body body;
//组合关系中的成员变量一般会在构造方法中赋值
Public People(Soul soul, Body body){
This.soul = soul;
This.body = body;
}

Public void study(){
System.out.println(“学习要用灵魂”+soul.getName());
}
Public void eat(){
System.out.println(“吃饭用身体:”+body.getName());
}
}

5.继承(Generalization)

继承表示类与类(或者接口与接口)之间的父子关系。在java中,用关键字extends表示继承关系。UML图例中,继承关系用实线+空心箭头表示,箭头指向父类。
6.实现(Implementation)

表示一个类实现一个或多个接口的方法。接口定义好操作的集合,由实现类去完成接口的具体操作。在java中使用implements表示。UML图例中,实现关系用虚线+空心箭头表示,箭头指向接口。