我参考的资料:
c语言中文网_软件设计模式概述
菜鸟设计模式
设计模式六大原则
《Android源码设计模式解析与实战》
《Android进阶之光》
设计模式分类
常见一共有23种,根据他们的行为可以分为三种,
- 一种是创建型模式包含5种(单例、工厂、抽象工厂、建造者、原型);
- 第二种行为型模式包含11种(策略、模板、观察者、迭代器、责任链、命令、备忘录,状态、访问者、中介者、解释器);
- 第三种结构型模式包含7种(适配器、装饰、代理、外观、桥接、组合、享元);
重要的思想↓
如果上面太多没记住或者太多了还没学咋整,就是要牢记于心,把下面6个原则 SOLID+Lod原则给融入自己写的每一行代码。
S: single responsibility principle 单一原则
O:open close principle 开闭原则
L: Liskov substitution principle 里氏替换原则
I: interface segregation principle 接口隔离原则
D: dependence inversion principle 依赖倒置原则
Lod: law of Demeter 迪米特法则(LKP least knowledge principle 最少知识原则)
还有个CRP 合成复用原则(Composite Reuse Principle)
单一原则SRP
书面描述:一个类是一堆相关性很高的方法和数据的封装,有且只有一个原因导致他更改。我的理解就是你一个方法是初始化就初始化,是播放就别干暂停的事情。对音乐文件编解码啥的跟播放有关系,但是是另一个职能,也给他抽离出去。一个类最好针对一个事情,比如你是个屏幕尺寸的工具类,就别放点什么保存文件之类的方法。
public void playMusic() {
//判断当前是否播放,再抽个方法
if(isPlaying) {
playManager.stop();
playManager.someThing();
}
//初始化,再抽个方法
thisSong.prepare();
thisSong.setParams();
playManager.start(thisSong);
}
public void playMusic(Song thisSong) {
checkPlayState();
prepareSong();
playManager.start(thisSong);
}
开闭原则OCP
书面描述就是对修改是关闭的,对于扩展是开放的;可以通过“抽象约束、封装变化”来实现开闭原则,即通过接口或者抽象类为软件实体定义一个相对稳定的抽象层,而将相同的可变因素封装在相同的具体实现类中。我理解就是都开发完了,要加新需求的时候,看看咋样才能不改原来的逻辑,然后还能给她加上新逻辑的。看看是不是一个事情要两个实现方案换着来,或者是加了新的功能。只要是一看要修改原来的代码,看看能不能通过抽取父类然后建立多个不同实现的子类,或者通过抽象接口,给他不同实现类啥的。
//开闭原则
public class OCPTest {
public static void main(String[] args) {
OCP ocp = new OCP();
//最开始我喜欢的哥哥,我自己组cp
ocp.createCP4GeGe();
//后来为了火跟别的流量大佬组cp
ocp.createCP4GeGe("with_popular_star");
//cp类型太多,交给了个组织,每个人负责一个不同类型的cp
ocp.createCP(new AdvertisingOCP());
//让跟一个会rap的人组cp
ocp.createCP(new RapCP());
//让哥哥会Rap...
ocp = new RapOCP();
ocp.createCP(new RapCP());
//上面这个大概是我理解的OCP了
}
static class OCP {
//最开始的方法
public void createCP4GeGe() {
System.out.println("gege跟我喜欢的明星在一起");
}
//需求逐渐增多,每增加一个都要改动这个方法。。。nonono
public void createCP4GeGe(String type) {
switch (type) {
case "with_popular_star":
System.out.println("蹭热度cp");
break;
case "to_promote_new_movie":
System.out.println("给新剧打广告cp");
break;
}
}
public void createCP(OhCP cp) {
cp.createCP();
}
}
static class RapOCP extends OCP {
@Override
public void createCP(OhCP cp) {
System.out.println("我也会rap");
super.createCP(cp);
}
}
interface OhCP {
void createCP();
}
static class RapCP implements OhCP {
String getSkill() {
return "rap";
}
@Override
public void createCP() {
System.out.printf("cp会%s", getSkill());
System.out.println();
}
}
static class AdvertisingOCP implements OhCP {
@Override
public void createCP() {
System.out.println("给新剧打广告cp");
}
}
}
上面那个例子估计有人问(我自己问:为啥有的用接口,有的用超类继承呢。。主要考虑到一个复用,还有一个是功能抽象接口和抽象类的区别)
里氏替换原则LSP
书面描述:所有引用基类的地方必须能透明地使用其子类的对象。我的理解是这个就要说到抽象和继承了,就是爸爸出现的地方都能替换成儿子,依赖抽象不依赖具体。比如爸爸(父类)已经跟买家定好了你先给钱,我后给货。那具体是大儿子取现金钱开车送货,还是二儿子刷卡开船送货都行,但是儿子不能更改爸爸定下的规矩(可以扩展,但是不能重写父类的方法)
public class LSPTest {
public static void main(String[] args) {
LSP lsp = new LSPSon1();
lsp.chargeMoney();
lsp.deliverCargo();
}
static abstract class LSP {
abstract void chargeMoney();
abstract void deliverCargo();
}
static class LSPSon1 extends LSP {
@Override
void chargeMoney() {
System.out.println("show me cash");
}
@Override
void deliverCargo() {
System.out.println("deliveries in a BMW");
}
}
static class LSPSon2 extends LSP {
@Override
void chargeMoney() {
System.out.println("credit card please");
}
@Override
void deliverCargo() {
System.out.println("deliveries with my jetSki");
}
}
}
接口隔离原则ISP
书面描述:一个类对另一个类的依赖应该建立在最小的接口上。我理解就是接口是抽象的功能定义,我一个类可以被复制、被比较、被读写,我抽取的时候把这个类的基本属性比如名字、id这些属性抽到了抽象类里,然后把它具有的这些特性都抽到一个功能接口A里,但是第二个类只能被读写,不能被复制、不能比较,那他也实现A的话,会有一些他不支持的属性,所以可以对A进行划分,比较A接口、复制B接口、读写C接口,如果还有个只支持读不支持写的类,看看是不是再划分一下C接口,这样实现类不会被强制实现一些用不到的方法。
//接口隔离原则
public class ISPTest {
interface IIO {
void read();
void write();
}
interface ICopy {
void copy();
}
interface ICompare {
void compareTo(Object obj);
}
interface IAllFunction {
void read();
void write();
void copy();
void compareTo(Object obj);
}
class BookFile implements IAllFunction{
@Override
public void read() {
}
@Override
public void write() {
}
@Override
public void copy() {
}
@Override
public void compareTo(Object obj) {
}
}
class BookFileII implements IIO,ICompare{
@Override
public void read() {
}
@Override
public void write() {
}
@Override
public void compareTo(Object obj) {
}
}
}
依赖倒置原则DIP
书面描述:高层模块不应该依赖于底层模块,两者应该依赖于其抽象;抽象不应该依赖具体实现(实现类),具体实现应该依赖抽象(接口或者抽象类)。我理解就是一个A调用我的方法,不是调我,是调我爸爸的抽象方法,他俩定义了个规则,然后具体实现让子类实现。面向接口编程了。
依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合
//依赖倒置原则
public class DIPTest {
public static void main(String[] args) {
Me me = new Me();
me.eatChipWithKetchup(new Ketchup());
me.eatChipWithCheese(new Cheese());
me.eatChipWithDip(new AppleSauce());
me.eatChipWithDip(new RoseJam());
}
static class Me {
//最开始我只吃番茄酱
void eatChipWithKetchup(Ketchup ketchup) {
ketchup.eatMe();
}
//后来我知道还有芝士酱
void eatChipWithCheese(Cheese cheese) {
cheese.eatMe();
}
//我爱的东西越来越多,我想蘸苹果酱
void eatChipWithAppleSauce() {
System.out.println("吃薯条蘸苹果酱");
}
//我不想每次换酱都写方法,直接让我跟蘸酱爸爸沟通,让他每次给我不同儿子就行
void eatChipWithDip(IDip dip) {
System.out.printf("吃薯条蘸%s", dip.getType());
}
}
interface IDip {
String getType();
}
static class Ketchup {
void eatMe() {
System.out.println("吃薯条蘸番茄酱");
}
}
static class Cheese {
void eatMe() {
System.out.println("吃薯条蘸芝士酱");
}
}
static class AppleSauce implements IDip {
@Override
public String getType() {
return "苹果酱";
}
}
static class RoseJam implements IDip {
@Override
public String getType() {
return "玫瑰酱";
}
}
}
迪米特法则LOD/最少知识原则LKP
书面描述:一个类应该对其他对象有最少的了解/只与直接的朋友通信(成员变量,方法参数,方法返回值中的类为直接朋友)(而出现在局部变量中的类不是直接的朋友)我理解就是每个类都做甩手掌柜,事情吩咐下去了,不管你是怎么实现的,我只用跟你说一声调你一个方法,该给你的信息告诉你,最后你干完这个事情就行了。
这个是从c语言中文网抄的,有些我还不太能用自己的话说出来,贴这里
从迪米特法则的定义和特点可知,它强调以下两点:
从依赖者的角度来说,只依赖应该依赖的对象。
从被依赖者的角度说,只暴露应该暴露的方法。所以,在运用迪米特法则时要注意以下 6 点。
在类的划分上,应该创建弱耦合的类。类与类之间的耦合越弱,就越有利于实现可复用的目标。
在类的结构设计上,尽量降低类成员的访问权限。
在类的设计上,优先考虑将一个类设置成不变类。
在对其他类的引用上,将引用其他对象的次数降到最低。
不暴露类的属性成员,而应该提供相应的访问器(set 和 get 方法)。
谨慎使用序列化(Serializable)功能。
//迪米特法则/最少知识原则
public class LODTest {
public static void main(String[] args) {
//我要买个手机才能读书
new OldMe().read(new Phone());
new NewMe().read(new PhoneII(), "ONE DAY");
}
//我自己要找到这本书再打开
static class OldMe {
Book book;
void read(Phone phone) {
book = new Book("ONE DAY");
phone.readBook(book);
}
}
//上层交互类,直接被调用的类
static class Phone {
void readBook(Book book) {
new ReaderAPP().openBook(book);
}
}
//app 功能类
static class ReaderAPP {
void openBook(Book book) {
System.out.println("book's name is " + book.getName());
}
}
//最底层数据类
static class Book {
String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// ---------------------------------------------------------------------------------
// 我告诉手机我想看书,并且告诉书名,就应该可以直接开始看
static class NewMe {
void read(PhoneII phone, String bookName) {
phone.readBook(bookName);
}
}
static class PhoneII {
//我也应该只要打开app,告诉他书名就不管了
ReaderAPPII app;
void readBook(String bookName) {
app = new ReaderAPPII();
app.read(bookName);
}
}
static class ReaderAPPII {
Book book;
void read(String bookName) {
book = new Book(bookName);
System.out.println("book's name is " + book.getName());
}
}
}