设计模式学习

预备知识:UML图

1. 泛化generation,也就是继承。表示"is-a"关系。用实线+空心箭头表示。
如:老虎类继承自动物类

2. 实现realization,也就是实现接口。用虚线+空心箭头表示。
如:大雁类实现了飞翔接口

3. 聚合aggregation。表示"has-a"关系,聚合是弱包含关系。
如:雁群里面有大雁。
Class YanQun {
private DaYan[] daYanArray;
}
聚合用空心菱形+直线表示。空心菱形在“雁群”端。

4. 组合composition。表示"contains-a"关系,组合是强包含关系。
如:大雁有翅膀。
Class DaYan {
private ChiBang chiBang;
public DaYan () {
chiBang = new ChiBang();
}
}
组合用实心菱形+直线表示。实心菱形在“大雁”端。

5. 关联association. 即一方知道另一方的存在。
如:企鹅与气候
Class QiE {
private QiHou qiHou;
}
关联用实线+箭头表示,箭头指向“气候”。(因为企鹅要知道气候,所以拿箭射它)

关联分为单项关联,双向关联,自身关联。企鹅与气候为单项关联,因为只企鹅知道气候,气候不知道企鹅。

6. 依赖dependency.表示"use-a"的关系
如:动物依赖于氧气和水
abstract Class Animal {
public xinChenDaiXie (YangQi yangQi, Shui shui) {

}
}
依赖用虚线+箭头表示。箭头指向氧气和水。因为动物要用氧气和水做新城代谢。

设计模式

一。创建型模式
1. 简单工厂
适用场景:设计一个计算器程序,里面包含两个操作数,以及一个运算符号。

[img]http://dl2.iteye.com/upload/attachment/0110/5268/9405564d-cbb2-3eee-bca3-8578a637a02a.jpg[/img]

重点关注工厂类:
public class SimpleFactory {
Operater oper = null;
public static Operater createOperater (String operater) {
switch (operater) {
case "+":
oper = new AddOperater();
break;
case "-":
oper = new ReduceOperater();
break;
...
}
}
}
客户端代码:
Operater oper = SimpleFactory.createOperater("-");
oper.setNumberA(9);
oper.setNumberB(5);
System.out.print("Result = " + oper.getResult());

总结:对于易于变化的地方(到底要实例化谁)用一个单独的类(工厂)来创建其实例。

2. 工厂方法
适用场景:设计一个计算器程序,里面包含两个操作数,以及一个运算符号。

[img]http://dl2.iteye.com/upload/attachment/0110/5264/26ee2bb2-5544-3182-b82d-a68b7f091838.jpg[/img]

与简单工厂不同的是,客户端调用的时候,先实例化具体工厂:
[b]IFactory factory = new AddFactory();[/b]
Operater operater = factory.createOperater();
operater.setNumberA(9);
operater.setNumberB(5);
System.out.println("Result = " + operater.getResult);

简单工厂与工厂方法的区别?
1) 简单工厂:在工厂类中加入了逻辑判断,动态实例化类,将客户端与具体产品解耦。
缺点:在增加新功能时,如增加乘法,则需改变工厂类的逻辑,违背了开闭原则。
2) 工厂方法:去除了简单工厂的缺点。定义了一个工厂接口,让子类决定实例化哪一个类。
缺点:每增加一个产品,即运算符,都要增加一个产品工厂类,造成每个产品与相应的工厂耦合。

3. 抽象工厂:解决了工厂方法一个类只能生产一个产品的弊端。
适用场景:对已有应用系统更换数据库

工厂方法:

[img]http://dl2.iteye.com/upload/attachment/0110/5260/2082c985-7c94-3066-8d04-cbc115b0f46f.jpg[/img]

抽象工厂:

[img]http://dl2.iteye.com/upload/attachment/0110/5262/f6fa8e18-3622-3555-863a-1c545f022d34.jpg[/img]

抽象工厂中的工厂会生产一个系列的产品,而不只是一种产品。

interfact IUser {} //定义User类型

//负责对SQLServer数据库的User类做增删改查
class SQLServerUser implements IUser {
public USer getUser() {
//去SQLServer对应的表中查到User,然后return
}
public void insert(IUser user) {
//把user插入到SQLServer对应的user表
}
}

//负责对Access数据库的User类做增删改查
class AccessUser implements IUser {
public User getUser() {
//去Access对应的表中查到User,然后return
}
public void insert(IUser user) {
//把user插入到Access对应的user表
}
}

interface IDepartment {} //定义Department类型

class SQLServerDepartment implements IDepartment {
public Department getDepartment() {
//去SQLServer对应的表中查到department,然后return
}
public void insert(IDepartment department) {
//把department插入到SQLServer对应的department表
}
}

class AccessDepartment implements IDepartment {
public Department getDepartment() {
//去SQLServer对应的表中查到department,然后return
}
public void insert(IDepartment department) {
//把department插入到SQLServer对应的department表
}
}

interface IFactory {
public IUser createUser();
public IUser createDepartment();
}

//生产Access数据的工厂
class AccessFactory implements IFactory {
public IUser createUser() {
return new AccessUser();
}

public IDepartment createDepartment() {
return new AccessDepartment();
}
}

//生产SQLServer数据的工厂
class SQLServerFactory implements IFactory {
public IUser createUser() {
return new SQLServerUser();
}

public IDepartment createDepartment() {
return new SQLServerDepartment();
}
}

客户端代码:
User user = new User();
Department department = new Department();

//IFactory sQLServerFactory = new SQLServerFactory();
IFactory accessFactory = new AccessFactory();
IUser accessUser = accessFactory.createUser();
accessUser.insert(user);
User u = accessUser.getUser();
IDepartment accessDepartment = accessFactory.createDepartment();
accessDepartment.insert(department);
Department d = accessDepartment.getDepartment();

从产品角度,分为两类(User类和Department类);从工厂角度,也分为两类(SQLServer类和Access类)。


4. 原型(prototype): 从一个对象为原型创建另一个对象。即:虚拟方法调用+对象的克隆。
适用场景:对象的克隆

[img]http://dl2.iteye.com/upload/attachment/0110/5295/5b185ba1-16ff-3ec6-bbf7-821d8178da8d.jpg[/img]

5. 单例(singleton):保证一个类只有一个实例,且自己实例化并向整个系统提供这个实例。
使用场景:在Flex项目的仪表盘中,每次用户设置完参数,都要确保只显示一个仪表盘。
线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计为单例。
单例分为3种:懒汉式、饿汉式、登记式

1. 懒汉式单例: 在调用getInstance时实例化对象,不是线程安全的
public class Singleton {
// 将构造器设为private
private Singleton() {}
// 注意此处没有final
private static Singleton instance = null;

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

2. 饿汗式单例:在类创建的同时就已经创建好一个static final的instance,以后不再改变,所以是线程安全的。
public class Singleton {
//将构造器设为private
private Singleton() {}
//在成员变量中自行实例化一个private static final的instance.
private static final instance = new Singleton();
//静态工厂方法
public static Singleton getInstance() {
return instance;
}
}

3. 登记式单例: 把单例的实例存在一个Map中,对于已经登记过的实例,直接从Map中取并且返回,对于没有登记的,则先登记,然后返回。

public class Singleton {
private static Map map = new HashMap ();
static {
Singleton instance = new Singleton();
map.put(instance.getClass().getName(), instance);
}
//构造器用protected修饰
protected Singleton() {}

//静态工厂方法
public static Singleton getInstance(String name) {
if (name == null) {
name = Singleton.class.getName();
System.out.println("name == null" + "--->name="+name);
}
if (map.get(name) == null) {
try {
map.put(name, (Singleton)Class.forName(name).getInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
return map.get(name);
}
}

懒汉式单例与饿汉式单例的区别:
1)线程安全:饿汉式线程安全,懒汉式线程不安全,若要懒汉式也线程安全,需要在getInstance方法上加入synchronized修饰。
2)资源加载:饿汉式在类创建的时候就会实例化一个对象,不管以后是否会使用该对象,缺点是会占一定内存,优点是调用时速度更快。

6. 建造者(build):将一个对象的构建与表示分离,使同样的构建过程可以用于不同的表示。
适用场景:构建汽车

[img]http://dl2.iteye.com/upload/attachment/0110/5297/fd2713c0-19dd-3c46-a317-b3da08d8b89a.jpg[/img]

//接口Builder会定义要创建对象的各个部件
public interface Builder {
void buildPartA(); //如汽车轮子
void buildPartB(); //如汽车方向盘
void buildPartC(); //如汽车发动机
}

//用一个具体的类ConcreteBuilder来创建复杂的对象
public class ConcreteBuilder implements Builder {
Part partA, partB, partC;
public void buildPartA() {...}
public void buildPartB() {...}
public void buildPartC() {...}
public Produce getResult() {...}
}

//用一个类Director来构建对象
public class Director {
private Builder builder;
public Director (Builder builder) {
this.builder = builder;
}

//将轮子、方向盘、发动机组装成汽车
public void construct() {
builder.createPartA();
builder.createPartB();
builder.createPartC();
}
}

//客户端调用
Builder builder = new ConcreteBuilder();
Director director = new Director(builder);
director.construct();
Produce produce = builder.getResult();

建造者模式使得用户只需要指定要构建的产品,而无需知道构建的细节。

二。结构型模式
1. 外观/门面 (Facade)
适用场景:
场景1.投资基金(一个客户只需要对于一个基金,而一个基金对应多只股票)
场景2.JDBC连DB: 对于不同的DB,SQL是不同的,但对于连接数据库时,都需要加载驱动、输入用户名密码来获取数据库连接Connection. 获取Connection的步骤可以作为Facade类。

[img]http://dl2.iteye.com/upload/attachment/0110/5303/6dde520b-4d32-37e9-bd5b-41c0c6ea6a0b.jpg[/img]

facade应用举例:用户操作基金

[img]http://dl2.iteye.com/upload/attachment/0110/5305/c5346a48-a14c-3db1-913a-b477a78cc767.jpg[/img]

class Fund {
Stock1 gu1;
Stock2 gu2;
Stock3 gu3;

public Fund() {
gu1 = new Stock1();
gu2 = new Stock2();
gu3 = new Stock3();
}

public void buyFund() {
gu1.buy();
gu2.buy();
gu3.buy();
}

public void sellFund() {
gu1.sell();
gu2.sell();
gu3.sell();
}
}

//客户端代码
Fond jijin = new Fund();
jijin.buy();
jijin.sell();

你可能感兴趣的:(设计模式)