设计模式 - 2) 策略模式

// 结账基类
public abstract class CashSuper
{
    public abstract double acceptCash(double money);
}

// 正常模式
public class CashNomal : CashSuper
{
    public override double acceptCash(double money)
    {
        return money;
    }
}

// 打 8 折
public class CashRebate : CashSuper
{
    private double moneyRebate = 1d;

    public CashRebate(string rebate)
    {
        moneyRebate = double.Parse(rebate);
    }

    public override double acceptCash(double money)
    {
        return money * moneyRebate;
    }
}

// 满减
public class CashReturn : CashSuper
{
    private double moneyCondition = 0.0d;
    private double moneyReturn = 0.0d;

    public CashReturn(string condition, string re)
    {
        moneyCondition = double.Parse(condition);
        moneyReturn = double.Parse(re);
    }

    public override double acceptCash(double money)
    {
        if (money < moneyCondition) return money;

        return money - Math.Floor(money / moneyCondition) * moneyReturn;
    }
}

// 调用不同算法的"接口"类
public class CashContext
{
    public CashSuper cs = null;

    public CashContext(string type)
    {
        switch (type)
        {
            case "正常":
                cs = new CashNomal();
                break;
            case "8 折":
                cs = new CashRebate("0.8");
                break;
            case "满 200 - 50":
                cs = new CashReturn("200", "50");
                break;
            default:
                break;
        }
    }

    public double GetResult(double money)
    {
        if (cs == null) return 0;

        return cs.acceptCash(money);
    }
}

// 业务通过"调用"类实现不同的算法,但内部算法具体如何实现的,外部业务不需要知道
CashContext CashContextObj = new CashContext(SelectedCostType.Name);
TotalPrice = CashContextObj.GetResult(double.Parse(CurPrice) * double.Parse(CurMul));

类似与简单工程,同样存在后续业务新增策略时,需要修改 CashContext 类的 CashContext(string type) 的问题,违法对修改封闭的原则;

例子:

<Window.Resources>
    <localCommon:BindingProxy x:Key="Proxy" Data="{Binding}" />
</Window.Resources>
<Grid Margin="20">
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="auto"/>            
    </Grid.RowDefinitions>
    <StackPanel>
        <StackPanel.Resources>
            <Style TargetType="TextBox">
                <Setter Property="Width" Value="120"/>
            </Style>
            <Style TargetType="StackPanel">
                <Setter Property="Margin" Value="10"/>
            </Style>
            <Style TargetType="Button">
                <Setter Property="Margin" Value="10 0"/>
                <Setter Property="Width" Value="55"/>
                <Setter Property="Height" Value="25"/>
                <Setter Property="BorderBrush" Value="Transparent"/>
                <Setter Property="Background" Value="LightSalmon"/>
            </Style>
        </StackPanel.Resources>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="单价:"/>
            <TextBox Text="{Binding CurPrice, UpdateSourceTrigger=PropertyChanged}"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="数量:"/>
            <TextBox Text="{Binding CurMul, UpdateSourceTrigger=PropertyChanged}"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="折扣:" />
            <ComboBox ItemsSource="{Binding CostTypeList}" Width="100" Background="Transparent" DisplayMemberPath="Name" SelectedItem="{Binding SelectedCostType}">                    
            </ComboBox>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
        <Button Content="确定" Uid="Sure"/>
            <Button Content="重置" Uid="Reset"/>
        </StackPanel>
    </StackPanel> 
    <Border Grid.Row="1" BorderBrush="LightGray" BorderThickness="1" Margin="10">
        <ListBox ItemsSource="{Binding VList}" x:Name="lb"> 
            <ListBox.ItemTemplate>
                <DataTemplate>                        
                    <StackPanel Orientation="Horizontal">
                        <StackPanel.Resources>
                            <localCommon:BindingProxy x:Key="ProxyItem" Data="{Binding}" />
                        </StackPanel.Resources>
                        <StackPanel.ContextMenu>
                            <ContextMenu> 
                                <MenuItem Header="del" Command="{Binding Source={StaticResource Proxy}, Path=Data.DelCommand}" CommandParameter="{Binding Source={StaticResource ProxyItem}, Path=Data}" />
                            </ContextMenu>
                        </StackPanel.ContextMenu>
                        <TextBlock Text="{Binding Price}" Width="350"/>
                        <TextBlock Text="x"/>
                        <TextBlock Text="{Binding Mul}"/>
                        <TextBlock Text=" 折扣:" Margin="15 0 0 0"/>
                        <TextBlock Text="{Binding Rebate}"/>                        
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>                
        </ListBox>
    </Border>
        
    <StackPanel Grid.Row="2">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="总价:" />
            <TextBlock Text="{Binding TureTotalPrice}" FontSize="19"  />
        </StackPanel>

        <StackPanel Orientation="Horizontal">
            <TextBlock Text="折扣后的总价:" />
            <TextBlock Text="{Binding TotalPrice}" FontSize="19"  />
        </StackPanel>                     
    </StackPanel>
</Grid>

xmal.cs
public partial class Window7 : Window
{
    public Window7()
    {
        InitializeComponent();
        this.DataContext = new Window7ViewModel() {};
        AddHandler(Button.ClickEvent, new RoutedEventHandler((this.DataContext as Window7ViewModel).Element_Click));
    }
}

public class BindingProxy : Freezable
{
    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}

public class DelegateCommand : ICommand
{
    public Action<object> ExecuteCommand = null;
    public Func<object, bool> CanExecuteCommand = null;
    public event EventHandler CanExecuteChanged;
    public DelegateCommand() { }

    public DelegateCommand(Action<object> act)
    {
        ExecuteCommand = act;
    }

    public bool CanExecute(object parameter)
    {
        if (CanExecuteCommand != null)
        {
            return CanExecuteCommand(parameter);
        }
        else
        {
            return true;                
        }
    }

    public void Execute(object parameter)
    {
        if (ExecuteCommand != null) this.ExecuteCommand(parameter);         
    }

    public void RaiseCanExecuteChanged()
    {
        if (CanExecuteChanged != null)
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }
    }
}

public class NotifyPropertyChanged : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// 属性更改通知
    /// </summary>
    /// <param name="propertyname">属性名称</param>
    public void OnProperty(string propertyname)
    {
        PropertyChangedEventHandler propertychanged = PropertyChanged;
        if (propertychanged != null)
        {
            propertychanged(this, new PropertyChangedEventArgs(propertyname));
        }
    }

    /// <summary>
    /// 属性更改通知
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="func">返回属性的lambda表达式</param>
    public void RaisePropertyChange<T>(Expression<Func<T>> func)
    {
        var body = func.Body as MemberExpression;
        if (body != null)
        {
            var propertyinfo = body.Member;
            if (propertyinfo != null)
            {
                PropertyChangedEventHandler propertychanged = PropertyChanged;
                if (propertychanged != null)
                {
                    propertychanged(this, new PropertyChangedEventArgs(propertyinfo.Name));
                }
            }
        }
    }
}

public class Window7ViewModel : NotifyPropertyChanged
{
    private string _CurPrice;
    public string CurPrice
    {
        get { return _CurPrice; }
        set
        {
            _CurPrice = value;
            RaisePropertyChange(() => CurPrice);
        }
    }

    private string _CurMul;
    public string CurMul
    {
        get { return _CurMul; }
        set
        {
            _CurMul = value;
            RaisePropertyChange(() => CurMul);
        }
    }

    private double _TureTotalPrice = 0.0d;
    /// <summary>
    /// 折扣后的总价格
    /// </summary>
    public double TureTotalPrice
    {
        get { return _TureTotalPrice; }
        set
        {
            _TureTotalPrice = value;
            RaisePropertyChange(() => TureTotalPrice);
        }
    }

    private double _TotalPrice = 0.0d;
    /// <summary>
    /// 总价格
    /// </summary>
    public double TotalPrice
    {
        get { return _TotalPrice; }
        set
        {
            _TotalPrice = value;
            RaisePropertyChange(() => TotalPrice);
        }
    }

    public ObservableCollection<VItem> _VList;
    /// <summary>
    /// 所有清单
    /// </summary>
    public ObservableCollection<VItem> VList
    {
        get
        {
            if (_VList == null)
            {
                _VList = new ObservableCollection<VItem>();
            }
            return _VList;
        }
        set
        {
            _VList = value;
            RaisePropertyChange(() => VList);
        }
    }

    public ObservableCollection<CostType> _CostTypeList;
    /// <summary>
    /// 所有折扣类型
    /// </summary>
    public ObservableCollection<CostType> CostTypeList
    {
        get
        {
            if (_CostTypeList == null)
            {
                _CostTypeList = new ObservableCollection<CostType>();
            }
            return _CostTypeList;
        }
        set
        {
            _CostTypeList = value;
            RaisePropertyChange(() => CostTypeList);
        }
    }

    public CostType SelectedCostType { get; set; }

    public DelegateCommand DelCommand { get; set; }
                
    public Window7ViewModel()
    {
        DelCommand = new DelegateCommand(new Action<object>(DelItem));

        CostTypeList.Add(new CostType() { Name = "正常"});
        CostTypeList.Add(new CostType() { Name = "8 折"});
        CostTypeList.Add(new CostType() { Name = "满 200 - 50"});
    }

    private void DelItem(object obj)
    {
        try
        {
            VItem item = obj as VItem;
            VList.Remove(item);

            CashContext CashContextObj = new CashContext(item.Rebate);
            TotalPrice -= CashContextObj.GetResult(double.Parse(item.Price) * double.Parse(item.Mul));
            TureTotalPrice -= double.Parse(item.Price) * double.Parse(item.Mul);
        }
        catch (Exception ex)
        {

        }
    }

    public void Element_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            UIElement element = (UIElement)e.Source;

            if (element == null) element = (UIElement)e.OriginalSource;

            if (element == null) return;

            switch (element.Uid)
            {
                case "Sure":
                    if (SelectedCostType == null)
                    {                            
                        MessageBox.Show("请选择折扣");
                        return;
                    }

                    CashContext CashContextObj = new CashContext(SelectedCostType.Name);

                    TotalPrice += CashContextObj.GetResult(double.Parse(CurPrice) * double.Parse(CurMul));

                    TureTotalPrice += double.Parse(CurPrice) * double.Parse(CurMul);

                    VList.Add(new VItem() { Price = CurPrice, Mul = CurMul,Rebate = SelectedCostType.Name });

                    ResetCur();
                    break;

                case "Reset":
                    VList.Clear();
                    ResetCur();
                    TotalPrice = 0;
                    TureTotalPrice = 0;
                    break;

                default:
                    break;
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("出错了:" + ex);
        }
    }    
    
    private void ResetCur()
    {
        CurPrice = string.Empty;
        CurMul = string.Empty;
    }
}

/// <summary>
/// 新增的每一项
/// </summary>
public class VItem : NotifyPropertyChanged
{
    private string _Price;
    public string Price
    {
        get { return _Price; }
        set
        {
            _Price = value;
            RaisePropertyChange(() => Price);
        }
    }

    private string _Mul;
    public string Mul
    {
        get { return _Mul; }
        set
        {
            _Mul = value;
            RaisePropertyChange(() => Mul);
        }
    }
    
    private string _Rebate;
    public string Rebate
    {
        get { return _Rebate; }
        set
        {
            _Rebate = value;
            RaisePropertyChange(() => Rebate);
        }
    }
}

/// <summary>
/// 折扣类型
/// </summary>
public class CostType
{
    public string Name { get; set; }
    public double Cost { get; set; }
}
posted @ 2020-12-15 22:46  鑫茂  阅读(100)  评论(0编辑  收藏  举报