定义算法簇,分别封装起来,让他们之间可以相互替换。
此模式让算法的实现独立于使用算法的客户。
- 封装变化
- 多用组合,少用继承
- 针对接口编程,不针对实现编程
鸭子:鸭子的飞行和叫的行为进行封装,不同种类的鸭子采用不同的实现。
// 鸭子的抽象类
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public Duck() {
}
public void setFlyBehavior(FlyBehavior fb) {
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior qb) {
quackBehavior = qb;
}
abstract void display();
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
public void swim() {
System.out.println("All ducks float, even decoys!");
}
}
public interface FlyBehavior {
public void fly();
}
public interface QuackBehavior {
public void quack();
}
public class ModelDuck extends Duck {
// 在构造时指定具体的实现
public ModelDuck() {
flyBehavior = new FlyNoWay();
quackBehavior = new Quack();
}
public void display() {
System.out.println("I'm a model duck");
}
}
一个对象状态改变时,其他对象都会受到通知。
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
public interface Observer {
public void update(int value);
}
可直接用jdk中的观察这模式
java.util.Observable
java.util.Observer
缺点:Observable是一个类,必须设计一个类继承它。关键方法被保护,无法组合到自己的对象。
不能满足需求时自己设计。
动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案
InputStream是被包装的组件,FilterInputStream是一个抽象的装饰者.
BufferedInputStream是一个具体的装饰者,它加入两种行为,利用缓冲输入改进性能, 用readline()方法(一次读一行)增强接口。
LineNumberInputStream加上了计算行数的功能。
又叫做静态工厂方法(Static Factory Method)模式,由一个工厂对象根据外界给定的信息,决定究竟应该创建哪个具体类的对象.
// 产品类
abstract class Product{
public abstract void Show();
}
//具体产品类A
class ProductA extends Product{
@Override
public void Show() {
System.out.println("生产出了产品A");
}
}
//具体产品类B
class ProductB extends Product{
@Override
public void Show() {
System.out.println("生产出了产品C");
}
}
//工厂类
class Factory {
//工厂类控制生产哪种商品, 使用者只需要调用工厂类的静态方法就可以实现产品类的实例化。
public static Product Manufacture(String ProductName){
switch (ProductName){
case "A":
return new ProductA();
case "B":
return new ProductB();
default:
return null;
}
}
}
- 将创建实例的工作与使用实例的工作分开,使用者不必关心类对象如何创建,实现了解耦;
- 工厂类违背了“开闭原则”,对系统的维护和扩展不利,在工厂方法模式中得到了一定的克服。
定义了一个创建对象的接口,子类决定实例化哪一个,把实例化推迟到了子类。
参考文档
// 抽象工厂类
abstract class Factory{
public abstract Product Manufacture();
}
// 抽象产品类
abstract class Product{
public abstract void Show();
}
//具体产品A类
class ProductA extends Product{
@Override
public void Show() {
System.out.println("生产出了产品A");
}
}
//具体产品B类
class ProductB extends Product{
@Override
public void Show() {
System.out.println("生产出了产品B");
}
}
//工厂A类 - 生产A类产品
class FactoryA extends Factory{
@Override
public Product Manufacture() {
return new ProductA();
}
}
//工厂B类 - 生产B类产品
class FactoryB extends Factory{
@Override
public Product Manufacture() {
return new ProductB();
}
}
//生产工作流程
public class FactoryPattern {
public static void main(String[] args){
//客户要产品A
FactoryA mFactoryA = new FactoryA();
mFactoryA.Manufacture().Show();
//客户要产品B
FactoryB mFactoryB = new FactoryB();
mFactoryB.Manufacture().Show();
}
}
- 更符合开-闭原则, 新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可。
- 每个具体工厂类只负责创建对应的产品
- 依赖倒置原则:依赖抽象,不要依赖具体类。
提供一个接口,用来创建有相互关系的一组对象。
- 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
- 主要解决接口选择的问题。
- 对于新的产品族符合开-闭原则;对于新的产品种类不符合开-闭原则.
确保一个类只有一个实例,并提供一个全局访问点。
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
// 私有化构造函数
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
缺点:
public class Singleton {
private static Singleton INSTANCE;
private Singleton (){}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
缺点:多线程不安全
改进:
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
缺点:性能低,同一时间只有一个线程可以getInstance()
public static Singleton getSingleton() {
if (INSTANCE == null) { // 第一次检查
synchronized (Singleton.class) {
if (INSTANCE == null) { // 第二次检查
INSTANCE = new Singleton();
}
}
}
return INSTANCE ;
}
缺点:instance = new Singleton()并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情:
JVM 的即时编译器中存在指令重排序的优化。最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,并使用。
改进:instance 变量声明成 volatile
public class Singleton {
private volatile static Singleton INSTANCE; //声明成 volatile
private Singleton (){}
public static Singleton getSingleton() {
if (INSTANCE == null) {
synchronized (Singleton.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
public class Singleton {
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例没有绑定关系,
* 而且只有被调用到才会装载,从而实现了延迟加载
*/
private static class SingletonHolder{
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static final Singleton instance = new Singleton();
}
/**
* 私有化构造方法
*/
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
简洁,自动支持序列化机制,绝对防止多次实例化。
将一个类的接口,转换成客户期望的另一个接口。让原本不兼容的类可以合作无间。
提供一个统一的接口,用来访问子系统的一群接口。外观定义了一个高层接口,让子系统更易使用。
最少知识原则:只和你的密友谈话。
一个对象应当对其他对象有尽可能少的了解,
模式 | 意图 |
---|---|
装饰者 | 不改变接口,但加入责任 |
适配器 | 将一个接口转换成另一个接口 |
外观 | 让接口更简单 |
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
模式扩展: 添加钩子方法,使子类可以控父类行为
提供一个方法顺序访问一个集合对象的各个元素,而不用暴露其内部的表示。
//Iterator.java
public interface Iterator {
public boolean hasNext();
public Object next();
}
//Container.java
public interface Container {
public Iterator getIterator();
}
单一职责
集合类的职责是管理某种聚合,如何进行遍历是另外一种职责。