1、开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里 氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里 氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现 抽象化的具体步骤的规范。
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
5、迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。
如果你没有认证学习过Java的设计模式,不理解托管语言的OOP设计方法,可能你的应用变得很结构化,对于项目管理、架构扩展来说将会存在很多问题,参看了目前国内很多应用发现很多代码完全就不是一个Java程序员写出来的,虽然能用但是这样设计对于日后的维护等方面将会有很严重的问题.
单例模式应该是日常使用最为广泛的一种模式了。他的作用是确保某个类只有一个实例,避免产生多个对象消耗过多的资源。比如对数据库的操作时,就可以使用单例模式。
介绍单例模式使用方法的文章有很多,可以参见你真的用对单例模式了吗?
优点:
(1)由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁的创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
(2)单例模式可以避免对资源的多重占用,例如一个文件操作,由于只有一个实例存在内存中,避免对同一资源文件的同时操作。
(3)单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如,可以设计一个单例类,负责所有数据表的映射处理。缺点:
(1)单例模式一般没有接口,扩展很困难,若要扩展,只能修改代码来实现。
(2)单例对象如果持有Context,那么很容易引发内存泄露。此时需要注意传递给单例对象的Context最好是Application Context。
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
使用场景:
(1)相同的方法,不同的执行顺序,产生不同的事件结果时。
(2)多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。
(3)产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用,这个使用建造者模式非常适合。优点:
(1)良好的封装性,使用建造者模式可以使客户端不必知道产品内部组成细节。
(2)建造者独立,容易扩展。
缺点:
(1)会产生多余的Builder对象及Director对象,消耗内存。
public interface Builder {
//创建部件A 比如创建汽车车轮
void buildPartA();
//创建部件B 比如创建汽车方向盘
void buildPartB();
//创建部件C 比如创建汽车发动机
void buildPartC();
//返回最后组装成品结果 (返回最后装配好的汽车)
Product getResult();
}
//Director 类,负责制造
public class Director {
private Builder builder;
public Director( Builder builder ) {
this.builder = builder;
}
// 将部件partA partB partC最后组成复杂对象
//这里是将车轮 方向盘和发动机组装成汽车的过程
public void construct() {
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
}
}
public class ConcreteBuilder implements Builder {
Part partA, partB, partC;
public void buildPartA() {
//这里是具体如何构建partA的代码
};
public void buildPartB() {
//这里是具体如何构建partB的代码
};
public void buildPartC() {
//这里是具体如何构建partB的代码
};
public Product getResult() {
//返回最后组装成品结果
};
}
public interface Product { }//产品
public interface Part { }//部件
//调用
ConcreteBuilder builder = new ConcreteBuilder();
Director director = new Director( builder );
director.construct();
Product product = builder.getResult();
现实开发中,Director一般被省略。而直接使用一个Builder来进行对象的组装,这个Builder通常为链式调用,他是将setter方法返回自身。代码大致如下:
new TestBuilder().setA("A").setB("B").create();
定义一个用于创建对象的接口,让子类决定实例化那个类。在任何需生成复杂对象的地方,都可以使用工厂方法模式。复杂对象适合使用工厂模式,用new就可以完成创建的对象无需使用工厂模式。
优点:
1.工厂方法模式完全符合设计原则,降低了对象之间的耦合。高层模块只需要知道产品的抽象类,其他的实现都不需要关心。
2.良好的封装性,代码结构清晰。扩展性好。
缺点:
每次我们为工厂方法模式添加新的产品时就要编写一个新的产品类。同时还要引入抽象层,这必然会导致类结构的复杂化,所以,在某些情况比较简单时,是否要使用工厂模式,需要设计者权衡利弊了。
public abstract class Product {
/**
* 产品类的抽象方法
* 由具体的产品类去实现
* */
public abstract void method();
}
public class ConcreteProductA extends Product {
@Override
public void method() {
System.out.println("我是产品A");
}
}
public class ConcreteProductB extends Product {
@Override
public void method() {
System.out.println("我是产品B");
}
}
public abstract class Factory {
/**
* 抽象工厂方法
* 具体由子类实现
*
* @return 具体的产品对象
* */
public abstract Product createProduct();
}
public class ConcreteFactory extends Factory {
/**
* 具体工厂类
* */
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
public class Client {
public static void main(String[] args) {
Factory factory = new ConcreteFactory();
Product product = factory.createProduct();
product.method();
}
}
上面这种方式可能不是很灵活,可以利用反射实现,如下:
public abstract class Factory {
/**
* 抽象工厂方法
* 具体由子类实现
*
* @param clz 产品对象类类型
*
* @return 具体的产品对象
* */
public abstract T createProduct(Class clz);
}
public class ConcreteFactory extends Factory {
/**
* 具体工厂类
* */
@SuppressWarnings("unchecked")
@Override
public T createProduct(Class clz) {
Product product = null;
try {
product = (Product) Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T)product;
}
}
public class Client {
public static void main(String[] args) {
Factory factory = new ConcreteFactory();
Product product = factory.createProduct(ConcreteProductB.class);
product.method();
}
}
//如果我们的工厂只有一个,我们可以进行简化,这种方式又称为简单工厂模式或者静态工厂模式。
public class Factory {
/**
* 抽象工厂方法
* 具体由子类实现
*
* @param clz 产品对象类类型
*
* @return 具体的产品对象
* */
public static T createProduct(Class clz) {
Product product = null;
try {
product = (Product) Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T)product;
}
}
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。
使用场景:
1.针对同一类型问题的多种处理方式,仅仅是具体行为有差别时。
2.需要安全地封装多种同一类型的操作时。
3.出现同一抽象类有多个子类,而又需要使用if-else或者switch-case来选择具体子类时。
需求:计算图书价格,初级会员没有折扣,中级会员打9折,高级会员打8折。如果一般写法,应该是if-else判断他是什么级别的会员,在计算相应的折扣。下面使用策略模式来进行实现。
public interface MemberStrategy {
/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double calcPrice(double booksPrice);
}
public class PrimaryMemberStrategy implements MemberStrategy{
/**
* 初级会员折扣
*/
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于初级会员的没有折扣");
return booksPrice;
}
}
public class IntermediateMemberStrategy implements MemberStrategy{
/**
* 中级会员折扣
*/
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于中级会员的折扣为10%");
return booksPrice * 0.9;
}
}
public class AdvancedMemberStrategy implements MemberStrategy{
/**
* 高级会员折扣
*/
@Override
public double calcPrice(double booksPrice) {
System.out.println("对于高级会员的折扣为20%");
return booksPrice * 0.8;
}
}
public class Price {
//持有一个具体的策略对象
private MemberStrategy strategy;
/**
* 构造函数,传入一个具体的策略对象
* @param strategy 具体的策略对象
*/
public Price(MemberStrategy strategy){
this.strategy = strategy;
}
/**
* 计算图书的价格
* @param booksPrice 图书的原价
* @return 计算出打折后的价格
*/
public double quote(double booksPrice){
return this.strategy.calcPrice(booksPrice);
}
}
public class Client {
public static void main(String[] args) {
//选择并创建需要使用的策略对象
MemberStrategy strategy1 = new AdvancedMemberStrategy();
//创建环境
Price price = new Price(strategy1);
//计算价格
double quote = price.quote(300);
System.out.println("图书的最终价格为:" + quote);
}
}
//结果
//对于高级会员的折扣为20%
//图书的最终价格为:240.0
责任链模式是行为型设计模式之一,它使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
1.多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
2.在请求处理者不明确的情况下向多个对象中的一个提交请求。
3.需要动态指定一组对象处理请求。
这个例子我觉得很贴切。我们在公司有各种原因需要报销费用,首先我们要找我们的上级领导去审批,报销额度如果在领导的权限范围内,那就审批通过,否则领导在找自己的上级去审批,以此类推。
//抽象领导类
public abstract class Leader {
/**
* 上级领导处理者
*/
protected Leader nextHandler;
/**
* 处理报账请求
*
* @param money 能批复的报账额度
*
*/
public final void handleRequest(int money){
System.out.println(getLeader());
if(money <=limit()){
handle(money);
}else{
System.out.println("报账额度不足,提交领导");
if(null != nextHandler){
nextHandler.handleRequest(money);
}
}
}
/**
* 自身能批复的额度权限
*
* @return 额度
*/
public abstract int limit();
/**
* 处理报账行为
*
* @param money 具体金额
*/
public abstract void handle(int money);
/**
* 获取处理者
*
* @return 处理者
*/
public abstract String getLeader();
}
//组长(额度1000):
public class GroupLeader extends Leader{
@Override
public int limit() {
return 1000;
}
@Override
public void handle(int money) {
System.out.println("组长批复报销"+ money +"元");
}
@Override
public String getLeader() {
return "当前是组长";
}
}
//主管(额度5000):
public class Director extends Leader{
@Override
public int limit() {
return 5000;
}
@Override
public void handle(int money) {
System.out.println("主管批复报销"+ money +"元");
}
@Override
public String getLeader() {
return "当前是主管";
}
}
//经理(额度10000):
public class Manager extends Leader{
@Override
public int limit() {
return 10000;
}
@Override
public void handle(int money) {
System.out.println("经理批复报销"+ money +"元");
}
@Override
public String getLeader() {
return "当前是经理";
}
}
//老板(额度…):
public class Boss extends Leader{
@Override
public int limit() {
return Integer.MAX_VALUE;
}
@Override
public void handle(int money) {
System.out.println("老板批复报销"+ money +"元");
}
@Override
public String getLeader() {
return "当前是老板";
}
}
//发起申请:
public class Client {
public static void main(String[] args) {
//构造各个领导对象
GroupLeader groupLeader = new GroupLeader();
Director director = new Director();
Manager manager = new Manager();
Boss boss = new Boss();
//设置上级领导处理者对象
groupLeader.nextHandler = director;
director.nextHandler = manager;
manager.nextHandler = boss;
//发起报账申请
groupLeader.handleRequest(8000);
}
}
//结果:
当前是组长
报账额度不足,提交领导
当前是主管
报账额度不足,提交领导
当前是经理
经理批复报销8000元
责任链模式非常灵活,请求的发起可以从责任链的任何一个节点开始,也可以改变内部的传递规则。比如主管不在,我们完全可以跨过主管直接从组长那里转到经理。
对于责任链中的一个处理者对象,有两个行为。一是处理请求,二是将请求传递到下一节点,不允许某个处理者对象在处理了请求后又将请求传送给上一个节点的情况。
对于一条责任链来说,一个请求最终只有两种情况。一是被某个处理对象所处理,另一个是所有对象均未对其处理,对于前一种情况我们称为纯的责任链模式,后一种为不纯的责任链。实际中大多为不纯的责任链。
View事件的分发处理
ViewGroup事件投递的递归调用就类似于一条责任链,一旦其寻找到责任者,那么将由责任者持有并消费掉该次事件,具体体现在View的onTouchEvent方法中返回值的设置,如果返回false,那么意味着当前的View不会是该次的责任人,将不会对其持有;如果返回true,此时View会持有该事件并不再向外传递。
1.优点
可以对请求者和处理者的关系解耦,提高代码的灵活性。
2.缺点
每次都需要对链中请求处理者遍历,如果处理者太多那么遍历必定会影响性能,特别是在一些递归调用者中,要慎用。
观察者模式是一个使用率非常高的模式,它最常用在GUI系统、订阅–发布系统。因为这个模式的一个重要作用就是解耦,将被观察者和观察者解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。比如安卓的开源项目EventBus、Otto、AndroidEventBus等事件总线类的和RxJava响应式编程其核心都是使用观察者模式。
观察者模式是一种行为类模式,它定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。
(1)关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系。
(2)事件多级触发场景。
(3)跨系统的消息交换场景,如消息队列、事件总线的处理机制。
这里举一个追剧的例子,平常为了不错过最新的电视剧我们会订阅或关注这个电视剧,当电视剧更新后会第一时间推送给我们,下来就简单实现一下。
//抽象观察者类
/**
* 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己
*/
public interface Observer {
/**
* 有更新
*
* @param message 消息
*/
public void update(String message);
}
/**
* 抽象被观察者类
*/
public interface Observable {
/**
* 推送消息
*
* @param message 内容
*/
void push(String message);
/**
* 订阅
*
* @param observer 订阅者
*/
void register(Observer observer);
}
/**
* 具体的观察者类,也就是订阅者
*/
public class User implements Observer {
@Override
public void update(String message) {
System.out.println(name + "," + message + "更新了!");
}
// 订阅者的名字
private String name;
public User(String name) {
this.name = name;
}
}
/**
* 具体的被观察者类,也就是订阅的节目
*/
public class Teleplay implements Observable{
private List list = new ArrayList();//储存订阅者
@Override
public void push(String message) {
for(Observer observer:list){
observer.update(message);
}
}
@Override
public void register(Observer observer) {
list.add(observer);
}
}
public class Client {
public static void main(String[] args) {
//被观察者,这里就是用户订阅的电视剧
Teleplay teleplay = new Teleplay();
//观察者,这里就是订阅用户
User user1 = new User("小明");
User user2 = new User("小光");
User user3 = new User("小兰");
//订阅
teleplay.register(user1);
teleplay.register(user2);
teleplay.register(user3);
//推送新消息
teleplay.push("xxx电视剧");
}
}
小明,xxx电视剧更新了!
小光,xxx电视剧更新了!
小兰,xxx电视剧更新了!
当ListView的数据发生变化时,调用Adapter的notifyDataSetChanged函数,这个函数又会调用DataSetObservable的notifyChanged函数,这个函数会调用所有观察者 (AdapterDataSetObserver) 的onChanged方法。这就是一个观察者模式!
1.优点
(1)观察者和被观察者之间是抽象耦合,应对业务变化。
(2)增强系统的灵活性和可扩展性。
2.缺点
在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。
访问者模式,顾名思义使用了这个模式后就可以在不修改已有程序结构的前提下,通过添加额外的“访问者”来完成对已有代码功能的提升。
1.定义
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。
2.使用场景
(1)对象结构比较稳定,但经常需要在此对象结构上定义新的操作。
(2)需要对一个对象结构中的对象进行很多不同的且不相关的操作,而需要避免这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。
情景:年终了,公司会给员工进行业绩考核。但是,不同领域的管理人员对于员工的评定标准不一样。现在员工有攻城狮和经理,评定者有CEO和CTO,我们假定CTO只关注攻城狮的代码量、经理的新产品数量,而CEO关注的是攻城狮的KPI和经理的KPI以及新产品数量。
/**
* 员工基类(Element)
*/
public abstract class Staff {
//员工姓名
public String name;
//员工KPI
public int kpi;
public Staff(String name) {
super();
this.name = name;
this.kpi = new Random().nextInt(10);
}
//接受Visitor的访问
public abstract void accept(Visitor visitor);
}
/**
* 攻城狮
*/
public class Engineer extends Staff{
private int codeLines;//代码数量
public Engineer(String name) {
super(name);
codeLines = new Random().nextInt(10 * 10000);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
//攻城狮这一年写的代码数量
public int getCodeLines(){
return codeLines;
}
}
/**
* 经理
*/
public class Manager extends Staff{
private int products;//产品数量
public Manager(String name) {
super(name);
products = new Random().nextInt(10);
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
//一年内做的产品数量
public int getProducts(){
return products;
}
}
/**
*Visitor类
*/
public interface Visitor {
/**
* 访问攻城狮类型
*/
public void visit(Engineer engineer);
/**
* 访问经理类型
*/
public void visit(Manager manager);
}
/**
*CEO访问者
*/
public class CEOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
System.out.println("攻城狮:" + engineer.name + ", KPI:" + engineer.kpi);
}
@Override
public void visit(Manager manager) {
System.out.println("经理:" + manager.name + ", KPI:" + manager.kpi
+ ", 新产品数量 :" + manager.getProducts());
}
}
/**
*CTO访问类
*/
public class CTOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
System.out.println("攻城狮:" + engineer.name + ", 代码数量:" + engineer.getCodeLines());
}
@Override
public void visit(Manager manager) {
System.out.println("经理:" + manager.name +", 产品数量 :" + manager.getProducts());
}
}
/**
*员工报表类
*/
//员工业务报表类(ObjectStructure)
public class BusinessReport {
List mStaffs = new LinkedList();
public BusinessReport() {
mStaffs.add(new Manager("王经理"));
mStaffs.add(new Engineer("攻城狮-A"));
mStaffs.add(new Engineer("攻城狮-B"));
mStaffs.add(new Manager("李经理"));
mStaffs.add(new Engineer("攻城狮-C"));
}
/**
* 为访问者展示报表
* @param visitor 如CEO、CTO
*/
public void showReport(Visitor visitor){
for(Staff staff : mStaffs){
staff.accept(visitor);
}
}
}
//Client访问
public class Client {
public static void main(String[] args) {
//构建报表
BusinessReport report = new BusinessReport();
System.out.println("===== 给CEO看报表 =====");
//设置访问者CEO
report.showReport(new CEOVisitor());
System.out.println("===== 给CTO看报表 =====");
//设置访问者CTO
report.showReport(new CTOVisitor());
}
}
//结果
===== 给CEO看报表 =====
经理:王经理, KPI:2, 新产品数量 :5
攻城狮:攻城狮-A, KPI:5
攻城狮:攻城狮-B, KPI:7
经理:李经理, KPI:9, 新产品数量 :8
攻城狮:攻城狮-C, KPI:1
===== 给CTO看报表 =====
经理:王经理, 产品数量 :5
攻城狮:攻城狮-A, 代码数量:26238
攻城狮:攻城狮-B, 代码数量:8282
经理:李经理, 产品数量 :8
攻城狮:攻城狮-C, 代码数量:47927
安卓中的著名开源库ButterKnife、Dagger、Retrofit都是基于APT(Annotation Processing Tools)实现。而编译注解核心依赖APT。当我们通过APT处理注解时,最终会将获取到的元素转换为相应的Element元素,以便获取到它们对应信息。
代理模式也称委托模式,是结构型设计模式之一。是应用广泛的模式之一。
1.定义
为其他对象提供一种代理以控制对这个对象的访问。
2.使用场景
当无法或不想直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。
书中例子:以小民诉讼的流程举例。那么需要代理律师代理,诉讼简单流程:提交申请–>进行举证–开始辩护–>诉讼完成。
诉讼接口类:
public interface ILawsuit {
/**
* 提交申请
*/
void submit();
/**
* 进行举证
*/
void burden();
/**
* 开始辩护
*/
void defend();
/**
* 诉讼完成
*/
void finish();
}
具体诉讼人小民:
public class XiaoMin implements ILawsuit{
@Override
public void submit() {
//小民申请仲裁
System.out.println("老板年底拖欠工资,特此申请仲裁!");
}
@Override
public void burden() {
//小民提交证据
System.out.println("这是合同书和过去一年的银行工资流水!");
}
@Override
public void defend() {
//铁证如山
System.out.println("证据确凿,不需要再说什么!");
}
@Override
public void finish() {
//结果
System.out.println("诉讼成功,判决老板即日起七天内结算工资!");
}
}
代理律师:
public class Lawyer implements ILawsuit{
private ILawsuit mLawsuit; //持有一个具体被代理者的引用
public Lawyer(ILawsuit lawsuit) {
this.mLawsuit = lawsuit;
}
@Override
public void submit() {
mLawsuit.submit();
}
@Override
public void burden() {
mLawsuit.burden();
}
@Override
public void defend() {
mLawsuit.defend();
}
@Override
public void finish() {
mLawsuit.finish();
}
}
开始仲裁:
public class Client {
public static void main(String[] args) {
//构造出诉讼人小民
ILawsuit xiaomin = new XiaoMin();
//构造一个代理律师,并将小民传递进去
ILawsuit lawyer = new Lawyer(xiaomin);
//律师提交申请
lawyer.submit();
//律师进行举证
lawyer.burden();
//律师代小民辩护
lawyer.defend();
//完成诉讼
lawyer.finish();
}
}
结果:
老板年底拖欠工资,特此申请仲裁!
这是合同书和过去一年的银行工资流水!
证据确凿,不需要再说什么!
诉讼成功,判决老板即日起七天内结算工资!
Java提供了一个便捷的动态代理接口InvocationHandler,我们来实现它:
public class DynamicPorxy implements InvocationHandler{
private Object obj; //被代理类的引用
public DynamicPorxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 调用被代理类对象的方法
Object result = method.invoke(obj, args);
return result;
}
}
这里我们通过invoke方法来调用具体的被代理方法。
修改后的Client类:
public class Client {
public static void main(String[] args) {
//构造出诉讼人小民
ILawsuit xiaomin = new XiaoMin();
//1.静态代理
//构造一个代理律师,并将小民传递进去
//ILawsuit lawyer = new Lawyer(xiaomin);
//--------------------------------------
//2.动态代理
//构造一个动态代理
DynamicPorxy proxy = new DynamicPorxy(xiaomin);
//获取被代理类小民的ClassLoader
ClassLoader loader = xiaomin.getClass().getClassLoader();
//动态构造一个代理者律师
ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance(loader, new Class[]{ ILawsuit.class }, proxy);
//律师提交申请
lawyer.submit();
//律师进行举证
lawyer.burden();
//律师代小民辩护
lawyer.defend();
//完成诉讼
lawyer.finish();
}
}
结果不变,由此可以看出动态代理通过一个代理类来处理N多个被代理类,其实质是对代理者与被代理者解耦。相对而言静态代理则只能为给定接口下的实现类做代理,如果接口不同那么就需要重新定义不同的代理类,较为复杂,但是静态代理更符合面向对象原则。具体使用哪种方式,根据个人喜好。
ActivityManagerProxy代理类
ActivityManager是Android中管理和维护Activity的相关信息的类,为了隔离它与ActivityManagerService,有效降低二者的耦合,在这中间使用了ActivityManagerProxy代理类,所有对ActivityManagerService的访问都转换成对代理类的访问,这样ActivityManager就与ActivityManagerService解耦了。
MVC全称是Model - View - Controller,是模型(model)-视图(view)-控制器(controller)的缩写。MVC是一种框架模式而非设计模式,GOF把MVC看作是3种设计模式:观察者模式、策略模式与组合模式的合体,而核心是观察者模式。简而言之,框架是大智慧,用来对软件设计进行分工;设计模式是小技巧,对具体问题提出解决方案,以提高代码复用率,降低耦合度。
1.MVC的优点
(1)首先就是理解比较容易,技术含量不高,这对开发和维护来说成本较低也易于维护与修改。
(2)耦合性不高,表现层与业务层分离各司其职,对开发来说很有利。
2.MVC的缺点
(1)完全理解MVC并不是很容易。使用MVC需要精心的计划,由于它的内部原理比较复杂,所以需要花费一些时间去思考。同时由于模型和视图要严格的分离,这样也给调试应用程序带来了一定的困难。每个构件在使用之前都需要经过彻底的测试。
(2)对于小项目,MVC反而会带来更大的工作量以及复杂性。
Android中对MVC的应用很经典,在android中视图View层一般采用XML文件进行界面的描述。如下例子:
"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:id="@+id/list_item_text"
android:textSize="16sp"
android:gravity="left|center_vertical"
android:padding="10dp" />
而对于模型Model部分则大多对应于本地的数据文件或网络获取的数据体,很多情况下我们对这些数据的处理也会在这一层中进行。
最后的控制器Controller则当之无愧的是右Activity承担。
在android中,业务逻辑和数据存取是紧紧耦合的,很多缺乏经验的开发者很可能会将各种各样的业务逻辑塞进某个Activity、Fragment或者自定义View中,这样会使得这些组件的单个类型臃肿不堪。如果不将具体的业务逻辑抽离出来,当UI变化时,你就需要去原来的View中抽离具体业务逻辑,这必然会很麻烦并且易出错。
(1)Presenter – 交互中间人:Presenter主要作为沟通View与Model的桥梁,它从Model层检索数据后,返回给View层,使得View与Model之间没有耦合,也将业务逻辑从View角色上抽离出来。
(2)View – 用户界面:View通常是指Activity、Fragment或者某个View控件,它含有一个Presenter成员变量。通常View需要实现一个逻辑接口,将View上的操作转交给Presenter进行实现,最后,Presenter 调用View逻辑接口将结果返回给View元素。
(3)Model – 数据的存取:Model 角色主要是提供数据的存取功能。Presenter 需要通过Model层存储、获取数据,Model就像一个数据仓库。更直白的说,Model是封装了数据库DAO或者网络获取数据的角色,或者两种数据方式获取的集合。
由于Presenter 经常性的持有Activity 的强引用,如果在一些请求结束之前Activity 被销毁了,那么Presenter 一直持有Activity 对象,使得Activity 对象无法回收,此时就会发生内存泄露。
那么解决方法就是采用弱引用和Activity、Fragment的生命周期来解决这个问题。首先建立一个Presenter 抽象:
public abstract class BasePresenter<T> {
protected Reference mViewRef; //View接口类型的弱引用
public void attachView(T view){
mViewRef = new WeakReference(view); //建立关联
}
protected T getView(){
return mViewRef.get(); //获取View
}
public boolean isViewAttached(){
return mViewRef != null && mViewRef.get() != null; //判断是否与View建立关联
}
public void detachView(){
if(mViewRef != null){
mViewRef.clear(); //解除关联
mViewRef = null;
}
}
}
通常这个View类型应该就是实现了某个特定接口的Activity或者Fragment等类型。
创建一个MVPBaseActivity基类,通过这个基类声明周期函数来控制它与Presenter 的关系。代码如下:
public abstract class MVPBaseActivity<V, T extends BasePresenter<V>> extends Activity {
protected T mPresenter; //Presenter对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = createPresenter();
mPresenter.attachView((V)this);
}
@Override
protected void onDestroy() {
super.onDestroy();
mPresenter.detachView();
}
protected abstract T createPresenter();
}