1. 单例设计模式
package com.hfw.smartfilebrowser.designmode;
import java.util.HashMap;
import java.util.Map;
public class Singleton {
public static void main(String[] args) {
for (int i=0; i<10; i++) {
System.out.println(E.INSTANCE);
}
}
}
class A {
private static A a = new A();
private A() {
}
public static A getInstance() {
return a;
}
}
class B {
private static B b;
private B() {
}
public synchronized static B getInstance() {
if (b == null) {
b = new B();
}
return b;
}
}
class C {
private static volatile C c;
private C() {
}
public static C getInstance() {
if (c == null) {
synchronized(C.class) {
if (c == null) {
c = new C();
}
}
}
return c;
}
}
class D {
private D() {
}
public static D getInstance() {
return DHolder.d;
}
private static class DHolder {
private static final D d = new D();
}
}
enum E {
INSTANCE;
public void doSomeThing() {
System.out.println("单例内部的方法");
}
}
class F {
private static Map<String, Object> map = new HashMap<>();
private F() {
}
public static void put(String key, Object value) {
if(!map.containsKey(key)) {
map.put(key, value);
}
}
public static Object get(String key) {
return map.get(key);
}
}
2. 简单工厂设计模式
- 拥有三种角色,一个工厂类,一个基类,一系列基类的派生类(或实现类),举例写个分享SDK
- 其使用场景是工厂类负责创建的对象比较少,用户只需要知道传给工厂类的参数就行了,而不需关系具体创建
- 优点: 用户根据参数获得实例,避免了直接实例化类,降低了耦合性
- 缺点: 简单工厂需要知道其所有要生成的类型,当类型过多是不适合使用,并且如果需求变动比如我要添加微博分享,那么就得修改工厂类,违背了开闭原则
interface ShareChannel {
void share();
}
class WeixinChannel implements ShareChannel {
@Override
public void share() {
}
}
class QQChannel implements ShareChannel {
@Override
public void share() {
}
}
class ShareChannelFactory {
public static ShareChannel createShareChannel(String type) {
switch (type) {
case "Weixin":
return new WeixinChannel();
case "QQ":
return new QQChannel();
}
}
}
3. 工厂方法模式
- 拥有4种角色,抽象工厂类、具体工厂类、基类(或接口),把简单工厂的实现修改一下
- 例子:比如微信分享WXAPIFactory.createWXAPI()、钉钉分享DDShareApiFactory.createDDShareApi()都是使用了工厂方法设计模式
- 对比简单工厂模式,当需求改变需要增加微博分享时我们只需要创建一个WeiboChannel就行了不需要去改变Factory,没有违背开闭原则
public class ShareTest {
public static void main(String[] args) {
CommonShareChannelFactory factory = new CommonShareChannelFactory();
WeixinChannel channel = factory.createShareChannel(WeixinChannel.class);
channel.share();
}
}
interface ShareChannel {
void share();
}
class WeixinChannel implements ShareChannel {
@Override
public void share() {
}
}
class QQChannel implements ShareChannel {
@Override
public void share() {
}
}
interface ShareChannelFactory {
<T extends ShareChannel> T createShareChannel(Class<T> clazz);
}
class CommonShareChannelFactory implements ShareChannelFactory {
@Override
public <T extends ShareChannel> T createShareChannel(Class<T> clazz) {
ShareChannel channel = null;
try {
channel = clazz.newInstance();
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
return (T) channel;
}
}
4. 建造者模式
- 主要用于创建一个复杂对象时使用,通过Builder类一步一步创建,比如Android中的AlertDialog其组成非常复杂,比如你可以只设置Title、Message,你也可以值设置Title,有很多种可选的设置,分享功能需要很多的参数,而很多参数都是可选的就可以使用建造者模式
- 优点 将部件与其组成过程分开,客户端只需要关注需要哪些部件,无需关心其实如何组成的
- 缺点 产生了多余的Build对象
public class ShareConstructorParams {
private String title;
private String content;
private String url;
private String imageUrl;
private ShareConstructorParams(Builder builder) {
this.title = builder.title;
this.content = builder.content;
this.url = builder.url;
this.imageUrl = builder.imageUrl;
}
public static class Builder {
private String title;
private String content;
private String url;
private String imageUrl;
public ShareConstructorParams.Builder setTitle(String title) {
this.title = title;
return this;
}
public ShareConstructorParams.Builder setContent(String content) {
this.content = content;
return this;
}
public ShareConstructorParams.Builder setUrl(String url) {
this.url = url;
return this;
}
public ShareConstructorParams.Builder setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
return this;
}
public ShareConstructorParams build() {
return new ShareConstructorParams(this);
}
}
public static void main(String[] args) {
ShareConstructorParams params = new ShareConstructorParams.Builder()
.setContent("我是分享内容")
.setImageUrl("http://xxx")
.setTitle("我是分享标题")
.setUrl("http://xxx")
.build();
}
}
5. 代理设计模式 分为静态代理和动态代理
- 静态代理
- 优点:防止与真实对象之间接触,降低耦合性,易于扩展,客户端可以完全不知道代理对象代理的是哪个真实对象
- 缺点:如果接口需要增加一个方法那么代理类也得实现该方法,把本来维护一个方法变成了维护两个方法
public class Proxy {
public static void main(String[] args) {
BuyerProxy proxy = new BuyerProxy();
proxy.buy();
}
interface IShop {
void buy();
}
static class RealBuyer implements IShop {
@Override
public void buy() {
System.out.println("真实的买家");
}
}
static class BuyerProxy implements IShop {
private IShop mIShop;
public BuyerProxy(IShop iShop) {
mIShop = new RealBuyer()
}
@Override
public void buy() {
System.out.println("我是代购的");
mIShop.buy();
}
}
}
- 动态代理
- 相对于静态代理其代理类不用在代码中写死,但是必须要有一个接口才能进行代理,因为java不支持多继承
package com.hefuwei.lwsbooks.designpattern;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy {
public static void main(String[] args) {
IShop proxy = (IShop) Proxy.newProxyInstance(DynamicProxy.class.getClassLoader(), new Class[] {IShop.class}, new MyInvocationHandler(new RealBuyer()));
proxy.buy();
}
interface IShop {
void buy();
}
static class RealBuyer implements IShop {
@Override
public void buy() {
System.out.println("RealBuyer");
}
}
static class MyInvocationHandler implements InvocationHandler {
private IShop iShop;
public MyInvocationHandler(IShop iShop) {
this.iShop = iShop;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("buy")) {
method.invoke(iShop);
}
return null;
}
}
}
6. 装饰模式
- 首先说说与代理模式的区别,前者(代理模式)客户端根据不知道代理对象内部究竟代理着哪个具体对象,后者被装饰的对象客户端完全知道,因为就是客户端传入的。
- 优点 可以在不改变被装饰类的情况下加强类的功能,或者类似Android里面的ContextWrap类,使其子类Activity、Service不必包含复杂的实现逻辑(比如startActivity)
public class Decorate {
static abstract class Context {
abstract void startActivity();
}
static class ContextWrap extends Context {
private Context mBase;
public ContextWrap(Context context) {
mBase = context;
}
@Override
void startActivity() {
mBase.startActivity();
}
}
static class ContextImpl extends Context {
@Override
void startActivity() {
System.out.println("真正的去startActivity");
}
}
public static void main(String[] args) {
ContextWrap wrap = new ContextWrap(new ContextImpl());
wrap.startActivity();
}
}
7. 外观模式
- 一般在封装SDK或者API时用到,暴露给客户端外观类(该类把子系统的功能进行结合)供客户端使用
- 优点:客户端无需关心具体的子系统的实现,直接与外观类进行交互,降低了耦合性,这样即使具体的子系统的内容发生改变,用户也不会感知到;同时由于客户端只能使用外观类的功能,而不能使用子系统的其他功能所以加强了安全性
- 缺点:不符合开闭原则,如果业务发生变更那么可能要直接修改外观类
- 下面假设用户有一台手机,手机有打电话系统和拍照系统,手机的外观类是MobilePhone,用户只能调用该类中的方法去执行操作,无法调用CallManager的privateFunction方法,因此加强了安全性
public class MobilePhone {
private CallManager callManager;
private CameraManager camaraManager;
public static void main(String[] args) {
MobilePhone phone = new MobilePhone();
phone.takePhotos();
phone.call();
}
public MobilePhone() {
callManager = new CallManager();
camaraManager = new CameraManager();
}
public void call() {
callManager.call();
callManager.hangup();
}
public void takePhotos() {
camaraManager.open();
camaraManager.takePhotos();
camaraManager.close();
}
}
class CallManager {
public void call() {
System.out.println("开始通话");
}
public void hangup() {
System.out.println("结束通话");
System.out.println("挂断电话");
}
public void privateFunction() {
System.out.println("内部才能调用的功能");
}
}
class CameraManager {
public void open() {
System.out.println("打开相机");
}
public void takePhotos() {
System.out.println("拍照");
}
public void close() {
System.out.println("关闭相机");
}
}
8. 享元设计模式
- 是池技术的重要实现技术,可以减少重复对象的创建,降低程序内部的占用,提高性能,一般拥有着以下三个角色 1. 抽象享元角色,同时定义出对象的外部状态和内部状态的接口。2. 具体享元角色,实例的抽象享元角色的业务。 3. 享元工厂,负责管理对象池和创建享元对象(一般内部用Map、SpareArray实现),如下面示例中的Ticket抽象类就是抽象享元角色内部的from、to属于内部状态,level(from to)属于外部状态会随着外界状态变化而变化;TrainTicket属于具体享元角色;TicketFactory属于享元工厂
- 好像其实就是缓存的一种,比如Java中的String一旦常量池有了就不会重新创建、Android中的Message通过一个链表来缓存、Volley里面的ByteArrayPool、OkHttp里面的连接池
public class FlyWeight {
public static abstract class Ticket {
protected String from;
protected String to;
protected SeatLevel level;
protected float price;
public Ticket(String from, String to, SeatLevel level, float price) {
this.from = from;
this.to = to;
this.level = level;
this.price = price;
}
abstract void showTicketInfo();
}
public static void main(String[] args) {
Ticket ticket1 = TicketFactory.getTicket("杭州东", "绍兴北", SeatLevel.SECOND_CLASS_SEAT);
ticket1.showTicketInfo();
Ticket ticket2 = TicketFactory.getTicket("杭州东", "绍兴北", SeatLevel.FIRST_CLASS_SEAT);
ticket2.showTicketInfo();
Ticket ticket3 = TicketFactory.getTicket("杭州东", "绍兴北", SeatLevel.SECOND_CLASS_SEAT);
ticket3.showTicketInfo();
}
public static class TrainTicket extends Ticket {
public TrainTicket(String from, String to, SeatLevel level, float price) {
super(from, to, level, price);
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public SeatLevel getLevel() {
return level;
}
public void setLevel(SeatLevel level) {
this.level = level;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
@Override
public void showTicketInfo() {
System.out.println("从" + from + " 到" + to + "的火车票" + level + "价格为" + price);
}
}
public enum SeatLevel {
BUSINESS_CLASS_SEAT("商务座"),
FIRST_CLASS_SEAT("一等座"),
SECOND_CLASS_SEAT("二等座");
private String desc;
SeatLevel(String desc) {
}
}
public static class TicketFactory {
private static HashMap<String, Ticket> map = new HashMap<>();
static Ticket getTicket(String from, String to, SeatLevel level) {
String key = from + to + level;
if (map.containsKey(key)) {
return map.get(key);
} else {
Ticket ticket = new TrainTicket(from, to, level, queryPrice(from, to, level));
map.put(key, ticket);
return ticket;
}
}
static float queryPrice(String from, String to, SeatLevel level) {
return (float) (Math.random() * 200);
}
}
}
9. 策略设计模式
- 使用场景,1. 针对同一类型的问题拥有多种解决方式,仅仅具体行为有差异;2. 有多个派生自同一个类的实现类又需要通过if-else、switch判断使用哪个的
- 优点 1. Context类依赖于抽象类ISort,不依赖与具体实现,Context只需要知道它操作的是一个ISort类就行了 2. 遵守了开闭原则,当添加了新的策略(ISort)时不需要修改Context类
- Android中的使用,比如Volley里面的Request,RequestQueue只依赖于抽象的Request类,当有新的Request实现不需要改变RequestQueue的代码;Volley里面的RetryPolicy,同样当有新的RetryPolicy时也不需要修改Request代码;RecyclerView的LayoutManager、Adapter
public class SortUtils {
public static final int BUBBLE_SORT = 1;
public static final int CHOOSE_SORT = 2;
public static void main(String[] args) {
List<Number> data = Arrays.asList(2, 4, 5, 2.4, 5.4, 1, 5, 12.2, 4.32, 5.45, 6, 7);
sort(data, BUBBLE_SORT);
sort(data, CHOOSE_SORT);
}
public static List<Number> sort(List<Number> source, int type) {
if (type == BUBBLE_SORT) {
return new BubbleSort().sort(source);
} else if (type == CHOOSE_SORT) {
return new ChooseSort().sort(source);
}
return null;
}
}
public class Context {
private ISort mISort;
public void setISort(ISort iSort) {
mISort = iSort;
}
public static void main(String[] args) {
Context strategy = new Context();
List<Number> data = Arrays.asList(2, 4, 5, 2.4, 5.4, 1, 5, 12.2, 4.32, 5.45, 6, 7);
strategy.setISort(new BubbleSort());
System.out.println(strategy.sort(data));
strategy.setISort(new ChooseSort());
System.out.println(strategy.sort(data));
}
public List<Number> sort(List<Number> list) {
if (mISort == null) {
throw new RuntimeException();
}
return mISort.sort(list);
}
}
10. 模板方法设计模式
- 主要有两种角色,1. 一个抽象父类 2. 多个派生自该抽象父类的子类
- 某个方法有些步骤是固定的,有些步骤是不固定的,就可以使用该模式,下面以BaseActivity为例,View.Draw()就是一个就是使用了目标方法模式
- 优点 将不变的行为搬移到超类,去除了子类中的重复代码
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected final void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initData();
initView();
initEvent();
}
protected void initEvent() {
}
protected abstract void initView();
protected void initData() {
}
}
11. 观察者设计模式
- 拥有4种角色,一个Observable接口或类、一个Observer接口、一个Observable的派生类、多个Observable接口的实现类
- 优点 观察者与被观察者是抽象耦合易于扩展
- 缺点 由于通知观察者是顺序通知的,如果一个观察者做的事情比较多造成了卡顿,那么就会影响其他后面的观察者
- 下面的代码微信公众号是被观察者,用户是观察者,其中hfw、cbw订阅了该微信公众号,而ym没有订阅,所以ym不会收到该微信公众号的推送(调用update),此外Android中的RecyclerView.Adapter、Receiver都是使用了观察者模式
public class ObserverPattern {
public static void main(String[] args) {
User hfw = new User("hfw");
User cbw = new User("cbw");
User ym = new User("ym");
WeixinOfficialAccounts accounts = new WeixinOfficialAccounts();
accounts.addObserver(hfw);
accounts.addObserver(cbw);
Article article = new Article();
article.setText("Hello, World !! Hello, World !! Hello, World !! Hello, World !!");
article.setPublicTime(new Date().toLocaleString());
accounts.addArticle(article);
}
static class WeixinOfficialAccounts extends Observable {
public void addArticle(Article article) {
setChanged();
notifyObservers(article);
}
}
static class User implements Observer {
private String mName;
public User(String name) {
mName = name;
}
@Override
public void update(Observable o, Object arg) {
System.out.println(mName + " 接受到了文章" + arg);
}
}
static class Article {
private String publicTime;
private String text;
public String getPublicTime() {
return publicTime;
}
public void setPublicTime(String publicTime) {
this.publicTime = publicTime;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
@NonNull
@Override
public String toString() {
return publicTime + " " + text;
}
}
}
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!hasChanged())
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
public interface Observer {
void update(Observable o, Object arg);
}