사용 시나리오
상태 패턴: 객체의 상태 변화에 따라 객체의 동작이 변경될 때 여러 판단 조건을 분리하고 동작의 변화를 캡슐화하기 위해 추상 상태 클래스를 정의하여 객체 동작을 제공할 수 있습니다. 상호 작용. 특정 상태 관련 동작은 해당 하위 클래스에 의해 구현됩니다.
전략 패턴: "전략"이라는 단어는 알고리즘과 동일합니다. 알고리즘이 실제 시스템에서 동적으로 지정되어야 하고 서로 대체될 수 있는 경우 알고리즘의 호출 인터페이스가 추상화될 수 있습니다. Liskov 대체 원칙에 따르면 상위 클래스가 나타날 때마다 해당 하위 클래스를 사용하여 이를 대체할 수 있으며 이는 비즈니스 요구 사항을 충족합니다.
비교
둘 다 상위 클래스의 표준 호출 인터페이스를 추상화하고 특정 동작은 하위 클래스에 의해 구현되며 환경 개체에도 상위 클래스에 대한 참조가 포함되어 있지만 두 패턴의 적용 시나리오는 완전히 다릅니다. . 예를 들어, 현금을 인출하기 위해 ATM에 갔을 때 계좌가 동결된 경우에는 정상적으로 돈을 인출할 수 없습니다. 여기에서 귀하의 은행 계좌에는 동결 및 동결 해제의 두 가지 상태가 있습니다. 그러한 비즈니스 솔루션을 해결하기 위해 전략 패턴을 사용할 생각은 없을 것입니다. 또 다른 예는 쇼핑몰 할인입니다. 어린이용 제품은 30% 할인되고, 노인용 제품은 50% 할인됩니다. 이 문제는 여기 제품에 노인용 제품이 있다고 말할 수 없습니다. 상태와 자식 상태!
ATM 인출 사례 분석
설계된 역할: 계산원, 계좌, ATM 기계.
사용 사례 다이어그램
간단함을 위해 출금 사용 사례를 분석해 보겠습니다.
기본 이벤트 경로
(1) 출금자는 은행 카드를 삽입하고 비밀번호를 입력합니다.
(2) 출금 작업을 선택하고 출금 금액을 입력합니다.
(3) 현금이 나올 때까지 기다립니다. 돈을 발행하고 인출합니다.
이 Use Case에서는 출금자의 계좌가 동결된 경우 선택적 이벤트 경로가 발생하고 출금 Use Case가 종료됩니다.
핵심 비즈니스 요구 사항은 사용자가 돈을 인출한다는 사실이므로 인출자와 출금자를 식별하는 두 가지 클래스에서 도메인 모델링을 시작할 수 있습니다. 출금자는 단순히 돈을 출금할 수 있는 유스케이스가 있다는 점을 고려하여 출금을 거래로 일반화합니다.
Modeling
Use Case Realization
Withdrawal: 기본 이벤트 경로 구현.
정제된 도메인 모델
여기서는 경계 객체 ATMSystem을 사용자와의 상호작용을 담당하는 컨트롤러(사용자와 상호작용하는 ATM 운영 인터페이스)로 소개하고, Trade는 사용자 트랜잭션 처리를 담당하는 클래스입니다.
출금자는 은행 카드를 삽입하고 비밀번호를 입력합니다. ATMSystem은 Trade 거래 클래스에 계좌 정보를 확인하는 메시지를 전달하는 역할을 담당합니다. Trade는 전달된 계좌 비밀번호를 기반으로 사용자가 존재하는지 확인한 후 처리 완료를 전달합니다. 사용자를 반영하기 위해 ATMSystem 경계 객체에 메시지를 보냅니다.
분석 모델의 일부 클래스
철회 설계 - 신청 상태 모드
계좌 상태는 동결 상태와 활성화 상태로 구분됩니다. 계좌가 활성화되면 거래를 할 수 있지만, 동결되면 거래를 할 수 없습니다. 계정 확인 시 현재 계정 상태를 반환해야 하며, 계정이 동결된 경우 출금 작업 수행 시 바로 오류 메시지가 반환됩니다. 상태 다이어그램은 다음과 같이 표시됩니다.
출금 신청 상태 모드 구조 다이어그램:
계정 확인 단계에서 계정이 동결되면 바로 DeadAccount로 돌아가 모든 거래가 거부됩니다. 그렇지 않으면 후속 거래를 처리하기 위해 ActiveAccount로 돌아갑니다.
도식 코드:
간단한 구현을 위해 경계 객체 ATMSystem은 여기에서 생략됩니다.
사용자 계정 정보 추상 클래스
/// <summary> /// 用户账号信息 /// </summary> public abstract class Account { /// <summary> /// 账号 /// </summary> private string account; /// <summary> /// 密码 /// </summary> private string pwd; public abstract decimal getBalance(decimal d); }
동결 계정 클래스
/// <summary> /// 冻结账户类 /// </summary> public class DeadAccount:Account { public override decimal getBalance(decimal d) { return 0; } }
激活账户类
/// <summary> /// 激活账户类 /// </summary> public class ActiveAccount:Account { public override decimal getBalance(decimal d) { return d; } }
交易类
/// <summary> /// 交易类 负责用户交易处理的类 /// </summary> public class Trade { /// <summary> /// 保存用户账号信息 /// </summary> private Account account; public Account VolidateLogin(Account a) { //query the database to validate the user exists //For Example this.account = new DeadAccount(); return this.account; } /// <summary> /// 商业逻辑 取款 /// </summary> /// <param name="d"></param> /// <returns></returns> public decimal GetBalance(decimal d) { return this.account.getBalance(d); } }
用户类
/// <summary> /// 取款人 /// </summary> public class User { /// <summary> /// 用户账号信息 /// </summary> private Account account; /// <summary> /// 交易处理类 /// </summary> private Trade trade; public User(Account a, Trade t) { this.account = a; tthis.trade = t; } /// <summary> /// 用户登录类 /// </summary> public void Login() { trade.VolidateLogin(account); } /// <summary> /// 取款 /// </summary> /// <param name="d"></param> /// <returns></returns> public decimal GetBalance(decimal d) { return trade.GetBalance(d); } }
客户端代码
class Client { static void Main(string[] args) { //开始用户取款,默认是激活账户 ActiveAccount aa = new ActiveAccount(); Trade t = new Trade(); User u = new User(aa,t); //先登录,后取款 u.Login(); Console.WriteLine(u.GetBalance(100)); Console.ReadLine(); } }
用户必须先登录(插入银行卡,输入密码,点确定),才能选择取款业务(选择取款)。登录之后,返回的账号对象作为trade类成员,当进行取款业务的时候直接引用该账号成员获得取款信息。如果该账号属于冻结账号,则直接返回0。否则返回取款的值。
商品折扣案例
案例描述:某家超市国庆节为了促销,某些类商品打折,比如运动鞋打8折、秋装打9折等,张三去购物为了一双运动鞋、一件秋装、一瓶洗发水。。。,张三买完东西回家,心想今天自己总共“赚”了多少钱?
案例分析:商家对于商品打折可能有很多策略,这里使用策略模式,封装商品打折策略,这样以便以后扩展了打折策略,不用去修改原来的代码,具有很好的灵活性。
模式涉及的角色:
抽象策略角色:通常由一个接口或者抽象实现;
具体策略角色:包装了相关的算法和行为;
环境角色:包含抽象策略角色的引用,最终供用户使用。
商品折扣案例设计图
顾客购物涉及到的角色有:购物车、商品、收银台、抽象策略角色和具体策略角色。
购物车:是摆放商品的容器,提供添加和删除操作;
商品:商品实体,有类型,商品名、价格等属性;
收银台:负责收钱,主要是计算顾客购买所有商品的价格和折扣总额;
抽象策略角色:提供折扣策略接口。
具体策略角色:实现具体折扣算法。
商品折扣示意代码:
/// <summary> /// 具体商品类 /// </summary> public class goods { /// <summary> /// 商品类型 /// </summary> public string Type { set; get; } /// <summary> /// 商品名称 /// </summary> public string Name { get; set; } /// <summary> /// 商品价格 /// </summary> public decimal Price { get; set; } }
抽象策略角色
/// <summary> /// 抽象策略接口 /// </summary> public interface IDiscountStrategy { decimal GetDiscount(goods g); }
具体策略角色
/// <summary> /// 秋装打折策略 /// </summary> public class AutumnDressDiscountStrategy:IDiscountStrategy { #region IDiscountStrategy Members public decimal GetDiscount(goods g) { return (decimal)0.9 * g.Price; } #endregion } /// <summary> /// 运动鞋打折策略 /// </summary> public class SportShoesDiscountStrategy:IDiscountStrategy { #region IDiscountStrategy Members public decimal GetDiscount(goods g) { return g.Price * (decimal)0.8; } #endregion }
购物车
/// <summary> /// 购物车类 负责商品的维护 /// </summary> public class ShoppingCar { private List<goods> goodsList=new List<goods>(); /// <summary> /// 将商品加入到购物车 /// </summary> /// <param name="g"></param> public void AddGoods(goods g) { goodsList.Add(g); } /// <summary> /// 将商品从购物车当中移除 /// </summary> /// <param name="g"></param> public void RemoveGoods(goods g) { goodsList.Remove(g); } public List<goods> GoodsList { get { return goodsList; } } } |
收银台角色
/// <summary> /// 收银台 /// </summary> public class CashierDesk { /// <summary> /// 购物车 /// </summary> private ShoppingCar shoppingCar; /// <summary> /// 策略字典 /// </summary> private Dictionary<string, IDiscountStrategy> strategies; public CashierDesk(ShoppingCar sc, Dictionary<string, IDiscountStrategy> s) { this.shoppingCar = sc; this.strategies = s; } /// <summary> /// 获得所有商品的价格 /// </summary> /// <returns></returns> public decimal GetTotalPrice() { return shoppingCar.GoodsList.Sum(p => p.Price); } /// <summary> /// 获得所有商品的总的折扣 /// </summary> /// <returns></returns> public decimal GetTotalDiscount() { decimal sum = 0; IDiscountStrategy idiscountStrategy; foreach (goods g in shoppingCar.GoodsList) { idiscountStrategy=strategies.SingleOrDefault(p => p.Key == g.Type).Value; if (idiscountStrategy != null) { sum += idiscountStrategy.GetDiscount(g); } } return sum; } }
客户端代码
class Client { static void Main(string[] args) { ShoppingCar sc = new ShoppingCar(); Dictionary<string, IDiscountStrategy> discountD = new Dictionary<string, IDiscountStrategy>(); //向购物车中加入商品 sc.AddGoods(new goods {Name="NIKE鞋 ",Price=100,Type="运动鞋" }); sc.AddGoods(new goods { Name = "秋装", Price = 200, Type = "秋装" }); sc.AddGoods(new goods { Name = "苹果", Price = 300, Type = "水果" }); //配置折扣策略 discountD.Add("运动鞋", new SportShoesDiscountStrategy()); discountD.Add("秋装", new AutumnDressDiscountStrategy()); CashierDesk cd = new CashierDesk(sc, discountD); //得到所有商品总价 Console.WriteLine(cd.GetTotalPrice()); //得到所有商品折扣价 Console.WriteLine(cd.GetTotalDiscount()); Console.ReadLine(); } }
策略模式优点与缺点:
优点
封装了算法不稳定性,易于以后业务策略的扩展。
缺点
每种策略对应于一个具体策略角色类,会增加系统需要维护的类的数量。
위 내용은 자바 디자인 패턴의 전략 패턴과 상태 패턴 분석 예시의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!