作者: 康凯森
日期: 2016-04-04
分类: 笔记
创建型模式涉及到对象实例化,这类模式都提供一个方法,将客户从所需要实例化的对象中解耦。
类和对象如何交互和分配职责
策略模式(Strategy)
状态模式(State)
责任链模式(Chain of Responsibility)
解释器模式(Interpreter)
命令模式(Command)
观察者模式(Observer)
备忘录模式(Memento)
迭代器模式(Iterator)
模板方法模式(Template Method)
访问者模式(Visitor)
中介者模式(Mediator)
让你把类和对象组合到更大的对象中
设计原则不可能完全遵循,但应该尽可能达到。
类应该对扩展开放,对修改关闭
子类可以扩展父类的功能,但不能改变父类原有的功能。
一个类应该只有一个引起变化的原因
要依赖抽象,不要依赖具体类
找出应用中可能发生变化的部分,和不需要改变的代码隔离开来
只和你的密友谈话
高层组件对待低层组件的方式是别调用我们,我们会调用你。 避免高层组件和低层组件之间的环状引用。
定义了对象之间一对多的依赖,当一个对象改变状态时,它的所有依赖者会收到通知并自动更新
出版者+订阅者 = 观察者模式
主题和观察者之间松耦合
public interface Subject {
//添加观察者
void attach(Observer o);
//删除观察者
void detach(Observer o);
//通知观察者
void notifyObservers();
//发生某事
void doSomeThings()
}
//观察者
public interface Observer {
void update();
}
public class ConcreteSubject implements Subject {
ArrayList<Observer> observers = new ArrayList<>();
@Override
public void attach(Observer o) {
observers.add(o);
}
@Override
public void detach(Observer o) {
observers.remove(o);
}
@Override
public void notifyObservers() {
for (Observer o : observers) {
o.update();
}
}
public void doSomeThings(){
//doSomeThings
notifyObservers();//通知观察者
}
}
//具体观察者
public class ConcreteObserver implements Observer {
@Override
public void update() {
System.out.println("我观察到subject发生了某事");
}
}
public static void main(String[] args) {
Subject cs = new ConcreteSubject();
//添加观察者
cs.attach(new ConcreteObserver());
//subject发生了某事,通知观察者
cs.doSomeThings();
}
装饰者模式将责任附加到对象上,若要扩展功能,装饰者提供比继承更有弹性的方案 增强功能。 装饰者可以在所委托被装饰者的行为之前或者之后,加上自己的行为,以达到特定目的。
//InputStream提供的基本方法(Component)
public abstract class InputStream implements Closeable {
}
//默认目标实现类(ConcreteComponent)
public class FileInputStream extends InputStream {
}
/*装饰实现类(FilterInputStream)一定是继承或实现原始接口(InputStream)的,内部有包含一个原始接口的超类(其实就是某个默认目标实现类)*/
//Decorator
public class FilterInputStream extends InputStream {
/**
* The input stream to be filtered.
*/
protected volatile InputStream in;
protected FilterInputStream(InputStream in) {
this.in = in;
}
}
//具体装饰类(ConcreteDecorator)
public class BufferedInputStream extends FilterInputStream {
public BufferedInputStream(InputStream in) {
this(in, DEFAULT_BUFFER_SIZE);
}
}
//具体装饰类(ConcreteDecorator)
public class DataInputStream extends FilterInputStream implements DataInput {
public DataInputStream(InputStream in) {
super(in);
}
}
在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。
Factory:工厂角色 工厂角色负责实现创建所有实例的内部逻辑
Product:抽象产品角色 抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口
ConcreteProduct:具体产品角色 具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
在以下情况下可以使用简单工厂模式:
工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。
工具类java.text.DateFormat,它用于格式化一个本地日期或者时间。
public final static DateFormat getDateInstance();
public final static DateFormat getDateInstance(int style);
public final static DateFormat getDateInstance(int style,Locale
locale);
获取不同加密算法的密钥生成器:
KeyGenerator keyGen=KeyGenerator.getInstance("DESede");
创建型模式对类的实例化过程进行了抽象,能够将对象的创建与对象的使用过程分离。
简单工厂模式又称为静态工厂方法模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
简单工厂模式包含三个角色:工厂角色负责实现创建所有实例的内部逻辑;抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口;具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。
简单工厂模式最大的优点在于实现对象的创建和对象的使用分离,将对象的创建交给专门的工厂类负责,但是其最大的缺点在于工厂类不够灵活,增加新的具体产品需要修改工厂类的判断逻辑代码,而且产品较多时,工厂方法代码将会非常复杂。
简单工厂模式适用情况包括:工厂类负责创建的对象比较少;客户端只知道传入工厂类的参数,对于如何创建对象不关心。
在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责哪一个产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。
Product:抽象产品 ConcreteProduct:具体产品 Factory:抽象工厂 ConcreteFactory:具体工厂
// 产品接口,定义一系列产品应该实现的服务,即产品的共性
interface IProduct {
public void method01();
public void method02();
}
// 具体的产品实现类
class ConcreteProductA implements IProduct {
public void method01() {
System.out.println("ConcreteProductA method01() ...");
}
public void method02() {
System.out.println("ConcreteProductA method02() ...");
}
}
class ConcreteProductB implements IProduct {
public void method01() {
System.out.println("ConcreteProductB method01() ...");
}
public void method02() {
System.out.println("ConcreteProductB method02() ...");
}
}
// 抽象的工厂类,定义了其子类必须实现的createProduct()方法
abstract class Factory {
//运用了Java 中的泛型和反射技术
public abstract <T extends IProduct> T createProduct(Class<T> c);
}
class ConcreteFactory extends Factory {
public <T extends IProduct> T createProduct(Class<T> c) {
T product = null;
try {
product = (T) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return product;
}
}
public class Client {
public static void main(String[] args) {
//创建一个具体工厂
Factory factory = new ConcreteFactory();
//根据参数中具体产品的.class名称来决定创建的产品类型
IProduct product01 = factory.createProduct(ConcreteProductA.class);
IProduct product02 = factory.createProduct(ConcreteProductB.class);
product01.method01();
product01.method02();
product02.method01();
product02.method02();
}
}
工厂方法模式又称为工厂模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
工厂方法模式包含四个角色:抽象产品是定义产品的接口,是工厂方法模式所创建对象的超类型,即产品对象的共同父类或接口;具体产品实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,它们之间往往一一对应;抽象工厂中声明了工厂方法,用于返回一个产品,它是工厂方法模式的核心,任何在模式中创建对象的工厂类都必须实现该接口;具体工厂是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户调用,返回一个具体产品类的实例。
工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。
工厂方法模式的主要优点是增加新的产品类时无须修改现有系统,并封装了产品对象的创建细节,系统具有良好的灵活性和可扩展性;其缺点在于增加新产品的同时需要增加新的工厂,导致系统类的个数成对增加,在一定程度上增加了系统的复杂性。
工厂方法模式适用情况包括:一个类不知道它所需要的对象的类;一个类通过其子类来指定创建哪个对象;将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定。
提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。
AbstractFactory:抽象工厂 ConcreteFactory:具体工厂 AbstractProduct:抽象产品 Product:具体产品
//CPU工厂接口
public interface CPUFactory {
public void createCPU();
}
//IntelCPU工厂
public class IntelCPU implements CPUFactory {
@Override
public void createCPU() {
System.out.println("Intel CPU");
}
}
//AMDCPU工厂
public class AMDCPU implements CPUFactory {
@Override
public void createCPU() {
System.out.println("AMD CPU");
}
}
//创建抽象工厂类接口
public interface Provider {
public CPUFactory createCPUFactory();
}
public class InterCPUFactory implements Provider {
@Override
public CPUFactory createCPUFactory() {
return new InterCPU();
}
}
public static void main(String[] args) {
//创建一个生产CPU工厂的工厂
Provider cpufactory = new InterCPUFactory();
//通过CPU工厂的工厂创建一个IntelCPU工厂
CPUFactory intelcpu = cpufactory.createCPUFactory();
//IntelCPU工厂生产intelCPU
intelcpu.createCPU();
}
1.产品类Product:一般是一个较为复杂的对象,也就是说创建对象的过程比较复杂,一般会有比较多的代码量。
2.抽象建造者类Builder: 将建造的具体过程交与它的子类来实现,这样更容易扩展。
3.建造者类ConcreteBuilder: 组建产品;返回组建好的产品。
4.指导类Director: 负责调用适当的建造者来组建产品,指导类一般不与产品类发生依赖关系,与指导类直接交互的是建造者类。
适用场景:需要生成的对象具有复杂的内部结构;需要生成的对象内部属性本身相互依赖。
//抽象生产者
public interface Builder {
void buildPartA();
void buildPartB();
void buildPartC();
Product buildProduct();
}
//具体生产者
public class ConcreteBuilder implements Builder {
Product product;
@Override
public void buildPartA() {
}
@Override
public void buildPartB() {
}
@Override
public void buildPartC() {
}
@Override
public Product buildProduct() {
return product;
}
}
//产品由各个组件组成
public class Product {
//partA
//partB
//partC
}
//指导者,产品生产流程规范
public class Director {
Builder builder;
//由具体的生产者来生产产品
public Director(Builder builder) {
this.builder = builder;
}
//生产流程
public void buildProduct(){
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
}
}
public static void main(String[] args) {
//只需要关心具体建造者,无需关心产品内部构建流程。
//如果需要其他的复杂产品对象,只需要选择其他的建造者.
Builder builder = new ConcreteBuilder();
//把建造者注入指导者
Director director = new Director(builder);
//指导者负责流程把控
director.buildProduct();
// 建造者返回一个组合好的复杂产品对象
Product product = builder.buildProduct();
}
确保一个类只有一个实例,并提供一个全局访问点。
多线程并发访问
1 需要频繁实例化然后销毁的对象。 2 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。 3 有状态的工具类对象。 4 频繁访问数据库或文件的对象。
有许多对象我们只需要一个:
class Solution {
/**
* @return: The same instance of this class every time
*/
private Solution(){
}
private static class SingletonHolder {
private static final Solution INSTANCE = new Solution();
}
public static Solution getInstance() {
return SingletonHolder.INSTANCE;
}
}
public static Singleton getInstance() {
//synchronized加锁同步会降低效率,这里先判断是否为空
//不为空则不需要加锁,提高程序效率
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
适配器模式是将一个类的接口转换为客户期望的另一个类的接口,适配器可以让原本不兼容的类可以合作无间。
1.目标抽象角色(Target):定义客户所期待的使用接口。(GVI接口)
2.源角色(Adaptee):需要被适配的接口。(HDMI接口)
3.适配器角色(Adapter):把源接口转换成符合要求的目标接口的设备。(HDMI-VGI转换器)
4.客户端(client):例子中指的VGI接口显示器。
//HDMI接口,需要被适配的接口
public interface HDMIPort {
void workByHDMI();
}
//VGI接口,客户端所期待的接口
public interface VGIPort {
void workByVGI();
}
//将HDMI接口转换为VGI,这就是适配器
public class HDMIToVGI implements VGIPort{
HDMIPort hdmiPort;
public HDMIToVGI(HDMIPort hdmiPort) {
this.hdmiPort = hdmiPort;
}
//将HDMI接口转换为VGI接口
@Override
public void workByVGI() {
hdmiPort.workByHDMI();
}
}
public static void main(String[] args) {
//定义一个HDMI接口
HDMIPort hdmiPort = new HDMIPort() {
@Override
public void workByHDMI() {
//hdmi接口工作方式
}
};
//将HDMI接口转换为VGI接口
VGIPort vgiPort = new HDMIToVGI(hdmiPort);
//经过转换HDMI接口变成了VGI接口
vgiPort.workByVGI();
}
为子系统中的一组统一的接口,用来访问子系统中的一群接口, 定义了一个高层接口,这个接口使得这一子系统更加容易使用。
public class CPU {
public void startup(){
System.out.println("启动CPU");
}
}
public class Memory {
public void startup(){
System.out.println("启动内存");
}
}
public class Disk {
public void startup(){
System.out.println("启动硬盘");
}
}
//facade
public class Computer {
CPU cpu;
Memory memory;
Disk disk;
public Computer(){
cpu = new CPU();
memory = new Memory();
disk = new Disk();
}
public void start(){
cpu.startup();
memory.startup();
disk.startup();
}
}
public static void main(String[] args) {
Computer computer = new Computer();
//启动computer是个很复杂的过程,我们并不需要知道其启动各个子系统的加载过程
//只需要调用computer为各个子系统提供统一的一个接口start()就可以启动computer了
computer.start();
}
定义一个操作中的算法的骨架,而将步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤
模板方法定义了一个算法的步骤,并允许子类为一个或多个方法提供实现。
//抽象模板类
public abstract class AbstractSort {
public abstract void sort(int[] array);
//防止子类覆盖使用final修饰
public final void printArray(int[] array) {
sort(array);
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}
//具体实现类
public class QuickSort extends AbstractSort {
@Override
public void sort(int[] array) {
//使用快排算法实现
}
}
public class MergeSort extends AbstractSort {
@Override
public void sort(int[] array) {
//使用归并排序算法实现
}
}
public static void main(String[] args) {
int[] arr = {3,5,2,45,243,341,111,543,24};
//AbstractSort s = new MergeSort();
AbstractSort s = new QuickSort();
s.printArray(arr);
}
提供一种方法顺序访问一个聚合对象中每个元素,而又不暴露内部的表示
封装“遍历每个集合内对象的过程”
能够让客户遍历你的对象但又不可以窥视你存储对象的方式
状态模式允许对象在内部状态改变时改变他的行为,对象看起来好像修改了它的类
游戏关卡
状态模式和策略模式的区别
意图不同
定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化
策略模式把对象本身和运算规则区分开来,其功能非常强大,因为这个设计模式本身的核心思想就是面向对象编程的多形性的思想。
在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能。
允许对象能够通过组合和委托来拥有不同的行为和算法。
抽象策略角色:策略类,通常由一个接口或者抽象类实现。
具体策略角色:包装了相关的算法和行为。
环境角色:持有一个策略类的引用,最终给客户端用的。
#定义一个Strategy接口,其中定义一个方法,用于计算。
public interface Strategy
{
public int calculate(int a, int b);
}
#定义具体的算法类,实现Strategy接口,算法类中的算法各自不同:加减乘等,但是外部调用形式符合接口的定义。
//加法
public class AddStrategy implements Strategy
{
@Override
public int calculate(int a, int b)
{
return a + b;
}
}
//减法
public class SubtractStrategy implements Strategy
{
@Override
public int calculate(int a, int b)
{
return a - b;
}
}
// 乘法
public class MultiplyStrategy implements Strategy
{
@Override
public int calculate(int a, int b)
{
return a * b;
}
}
#定义具体的环境角色,持有Strategy接口的引用,并且有get和set方法可以完成策略更换。在环境角色中调用接口的方法完成动作。
public class Environment
{
private Strategy strategy;
public Environment(Strategy strategy)
{
this.strategy = strategy;
}
public Strategy getStrategy()
{
return strategy;
}
public void setStrategy(Strategy strategy)
{
this.strategy = strategy;
}
public int calculate(int a, int b)
{
return strategy.calculate(a, b);
}
}
#这样在Client外部调用时,只需向环境角色设置相应的算法类,然后就可以得到相应的结果。
public class Client
{
public static void main(String[] args)
{
AddStrategy addStrategy = new AddStrategy();
Environment environment = new Environment(addStrategy);
System.out.println(environment.calculate(4, 3));
//减法
SubtractStrategy subStrategy = new SubtractStrategy();
environment.setStrategy(subStrategy);
System.out.println(environment.calculate(4, 3));
//乘法
MultiplyStrategy multiplyStrategy = new MultiplyStrategy();
environment.setStrategy(multiplyStrategy);
System.out.println(environment.calculate(4, 3));
}
}
#!/usr/bin/python
#环境角色
class Duck:
def display(self):
pass
def setFlyBehavior(self,fb):
self.flyBehavior = fb
def setQuackBehavior(self,qb):
self.quackBehavior = qb
def performQuack(self):
self.quackBehavior.quack()
def performFly(self):
self.flyBehavior.fly()
#抽象策略角色
class FlyBehavior:
def fly(self):
pass
#具体策略角色
class FlyWithWings(FlyBehavior):
def fly(self):
print "Fly with wings."
#具体策略角色
class FlyNoWay(FlyBehavior):
def fly(self):
print "Fly no way."
#抽象策略角色
class QuackBehavior:
def quack(self):
pass
#具体策略角色
class Quack(QuackBehavior):
def quack(self):
print "gua gua"
#具体策略角色
class Squeak(QuackBehavior):
def quack(self):
print "zhi zhi"
#具体策略角色
class MuteQuack(QuackBehavior):
def quack(self):
print "nothing"
#客户端
class MallardDuck(Duck):
def __init__(self):
self.setFlyBehavior(FlyWithWings())
self.setQuackBehavior(Squeak())
def display(self):
print "MallardDuck"
class RedheadDuck(Duck):
def __init__(self):
self.setFlyBehavior(FlyWithWings())
self.setQuackBehavior(Quack())
def display(self):
print "RedheadDuck"
class RubberDuck(Duck):
def __init__(self):
self.setFlyBehavior(FlyNoWay())
self.setQuackBehavior(MuteQuack())
def display(self):
print "RubberDuck"
class DecoyDuck(Duck):
def __init__(self):
self.setFlyBehavior(FlyWithWings())
self.setQuackBehavior(MuteQuack())
def display(self):
print "DecoyDuck"
for n in MallardDuck(),RedheadDuck(),RubberDuck(),DecoyDuck():
n.display()
n.performFly()
n.performQuack()
print
n.setFlyBehavior(FlyNoWay())
n.setQuackBehavior(Quack())
n.display()
n.performFly()
n.performQuack()
多个模式一起组合适用