设计模式需要遵从的原则
开闭原则:对扩展开放,对修改关闭。其含义是说应该通过扩展来实现变化, 而不是通过修改已有的代码来实现变化。
里氏代换原则:只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
依赖倒转原则:这个是开闭原则的基础,对接口编程,依赖于抽象而不依赖于具体。
接口隔离原则:使用多个隔离的借口来降低耦合度。客户端不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口上。
最少知道原则:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
合成复用原则:原则是尽量使用合成/聚合的方式,而不是使用继承。继承实际上破坏了类的封装性,超类的方法可能会被子类修改。
总结:
- 单一职责原则要求实现类要职责单一;
- 里氏替换原则要求不要去破坏继承系统;
- 依赖倒置原则要求面向接口编程;
- 接口隔离原则要求在设计接口的时候要精简单一;
- 迪米特法则要求要降低耦合;
- 开闭原则是总纲,要求对扩展开发,对修改关闭。
设计模式常用类型
创建型模式:工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。
结构型模式:适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
行为型模式:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
1、工厂模式
常用的工厂模式是静态工厂,利用static方法,作为一种类似于工具类Utils的辅助效果,一般情况下工厂类不需要实例化。
interface Type{}
class A implements Type{}
class B implements Type{}
public class StaticFactory {
private StaticFactory(){}
public static Type getA(){ return new A(); }
public static Type getB(){ return new B(); }
}
class Client{
// 客户端代码只需要将相应的参数传入即可得到对象
// 用户不需要了解工厂类内部的逻辑。
public static void main(String[] args){
System.out.println(StaticFactory.getA());
System.out.println(StaticFactory.getB());
}
}
2、抽象工厂模式
一个基础接口定义了功能,每个实现接口的子类就是产品,然后定义一个工厂接口,实现了工厂接口的就是工厂,这时候,接口编程的优点就出现了,我们可以新增产品类(只需要实现产品接口),只需要同时新增一个工厂类,客户端就可以轻松调用新产品的代码。
抽象工厂的灵活性就体现在这里,无需改动原有的代码,毕竟对于客户端来说,静态工厂模式在不改动StaticFactory类的代码时无法新增产品,如果采用了抽象工厂模式,就可以轻松的新增拓展类。
interface Type{}
class A implements Type{}
class B implements Type{}
interface Produce{
Type get();
}
class FactoryForA implements Produce{
@Override
public Type get() {
return new A();
}
}
class FactoryForB implements Produce{
@Override
public Type get() {
return new B();
}
}
public class AbstractFactory {
public static void main(String[] args){
System.out.println(new FactoryForA().get());
System.out.println(new FactoryForB().get());
}
}
3、单例模式
在内部创建一个实例,构造器全部设置为private,所有方法均在该实例上改动,在创建上要注意类的实例化只能执行一次,可以采用许多种方法来实现,如Synchronized关键字,或者利用内部类等机制来实现。
懒汉式(线程不安全,延迟初始化,严格意义上不是单例模式)
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉式(线程安全,比较常用,但容易产生垃圾,因为一开始就初始化 )
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
双重锁模式(线程安全,延迟初始化。这种方式采用双锁机制,安全且在多线程情况下能保持高性能)
public class Singleton {
private volatile static Singleton instance;
private Singleton (){}
public static Singleton getSingleton() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
4、建造者模式
public class Builder {
static class Student{
String name = null;
int number = -1;
String sex = null;
int age = -1;
String school = null;
// 构建器,利用构建器作为参数来构建Student对象
static class StudentBuilder{
String name = null;
int number = -1;
String sex = null;
int age = -1;
String school = null;
public StudentBuilder setName(String name) {
this.name = name;
return this;
}
public StudentBuilder setNumber(int number) {
this.number = number;
return this;
}
public StudentBuilder setSex(String sex) {
this.sex = sex;
return this;
}
public StudentBuilder setAge(int age) {
this.age = age;
return this;
}
public StudentBuilder setSchool(String school) {
this.school = school;
return this;
}
public Student build() {
return new Student(this);
}
}
public Student(StudentBuilder builder){
this.age = builder.age;
this.name = builder.name;
this.number = builder.number;
this.school = builder.school;
this.sex = builder.sex;
}
}
public static void main( String[] args ){
Student a = new Student.StudentBuilder().setAge(13).setName("LiHua").build();
Student b = new Student.StudentBuilder().setSchool("sc").setSex("Male").setName("ZhangSan").build();
}
}
5、原型模式
原型模式就是讲一个对象作为原型,使用clone()方法来创建新的实例。
public class Prototype implements Cloneable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
public static void main ( String[] args){
Prototype pro = new Prototype();
Prototype pro_copy = (Prototype)pro.clone();
System.out.println(pro_copy);
}
}
6、观察者模式
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖它的对象都会得到通知并自动更新。
// 实现了维护装有观察者引用集合的功能。
public class Subject {
// 保存注册的观察者对象
private List<Observer> mObervers = new ArrayList<>();
// 注册观察者对象
public void attach(Observer observer) {
mObervers.add(observer);
}
// 注销观察者对象
public void detach(Observer observer) {
mObervers.remove(observer);
}
// 通知所有注册的观察者对象
public void notifyEveryOne(String newState) {
for (Observer observer : mObervers) {
observer.update(newState);
}
}
}
// 观察者
public class ConcreteSubject extends Subject {
private String state;
public String getState() {
return state;
}
public void change(String newState) {
state = newState;
// 状态发生改变,通知观察者
notifyEveryOne(newState);
}
}
// 抽象出了一个及时更新的方法
interface Observer {
void update(String newState);
}
// 观察者
public class ObserverA implements Observer {
// 观察者状态
private String observerState;
@Override
public void update(String newState) {
// 更新观察者状态,让它与目标状态一致
observerState = newState;
}
}
// 观察者
public class ObserverB implements Observer {
// 观察者状态
private String observerState;
@Override
public void update(String newState) {
// 更新观察者状态,让它与目标状态一致
observerState = newState;
}
}
7、装饰模式
给一类对象增加新的功能,装饰方法与具体的内部逻辑无关。
interface Source{
void method();
}
public class Decorator implements Source{
private Source source;
public void decotate1(){
System.out.println("decorate");
}
@Override
public void method() {
decotate1();
source.method();
}
}
8、代理模式
客户端通过代理类访问,代理类实现具体的实现细节,客户只需要使用代理类即可实现操作。
这种模式可以对旧功能进行代理,用一个代理类调用原有的方法,且对产生的结果进行控制。
interface Source{
void method();
}
class OldClass implements Source{
@Override
public void method() {}
}
class Proxy implements Source{
private Source source = new OldClass();
void doSomething(){}
@Override
public void method() {
new Class1().Func1();
source.method();
new Class2().Func2();
doSomething();
}
}
9、外观模式
为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用。这句话是百度百科的解释,有点难懂,但是没事,看下面的例子,我们在启动停止所有子系统的时候,为它们设计一个外观类,这样就可以实现统一的接口,这样即使有新增的子系统subSystem4,也可以在不修改客户端代码的情况下轻松完成。
public class Facade {
private subSystem1 subSystem1 = new subSystem1();
private subSystem2 subSystem2 = new subSystem2();
private subSystem3 subSystem3 = new subSystem3();
public void startSystem(){
subSystem1.start();
subSystem2.start();
subSystem3.start();
}
public void stopSystem(){
subSystem1.stop();
subSystem2.stop();
subSystem3.stop();
}
}
10、桥接模式
interface DrawAPI {
public void drawCircle(int radius, int x, int y);
}
class RedCircle implements DrawAPI {
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("Drawing Circle[ color: red, radius: "
+ radius +", x: " +x+", "+ y +"]");
}
}
class GreenCircle implements DrawAPI {
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("Drawing Circle[ color: green, radius: "
+ radius +", x: " +x+", "+ y +"]");
}
}
abstract class Shape {
protected DrawAPI drawAPI;
protected Shape(DrawAPI drawAPI){
this.drawAPI = drawAPI;
}
public abstract void draw();
}
class Circle extends Shape {
private int x, y, radius;
public Circle(int x, int y, int radius, DrawAPI drawAPI) {
super(drawAPI);
this.x = x;
this.y = y;
this.radius = radius;
}
public void draw() {
drawAPI.drawCircle(radius,x,y);
}
}
11、组合模式
组合模式是为了表示那些层次结构,同时部分和整体也可能是一样的结构,常见的如文件夹或者树。
abstract class component{}
class File extends component{ String filename;}
class Folder extends component{
// 既可以放文件File类,也可以放文件夹Folder类。Folder类下又有子文件或子文件夹。
component[] files ;
String foldername ;
public Folder(component[] source){ files = source ;}
public void scan(){
for (component f:files){
if (f instanceof File){
System.out.println("File "+((File) f).filename);
}else if(f instanceof Folder){
Folder e = (Folder)f ;
System.out.println("Folder "+e.foldername);
e.scan();
}
}
}
}
12、享元模式
使用共享对象的方法,用来尽可能减少内存使用量以及分享资讯。通常使用工厂类辅助,例子中使用一个HashMap类进行辅助判断,数据池中是否已经有了目标实例,如果有,则直接返回,不需要多次创建重复实例。
abstract class flywei{ }
public class Flyweight extends flywei{
Object obj ;
public Flyweight(Object obj){
this.obj = obj;
}
}
class FlyweightFactory{
private HashMap<Object,Flyweight> data;
public FlyweightFactory(){ data = new HashMap<>();}
public Flyweight getFlyweight(Object object){
if ( data.containsKey(object)){
return data.get(object);
}else {
Flyweight flyweight = new Flyweight(object);
data.put(object,flyweight);
return flyweight;
}
}
}